From 4109c7b49739304f1ad393bd15a2069059c4ffe7 Mon Sep 17 00:00:00 2001 From: server Date: Wed, 22 Jan 2025 22:15:16 -0500 Subject: [PATCH 1/1] Wed Jan 22 10:15:16 PM EST 2025 --- Makefile | 2 + README.md | 140 ++++ build/idyll | Bin 0 -> 53072 bytes examples/arrays.ib | 20 + examples/err.ib | 17 + examples/fibonacci.ib | 17 + examples/loop.ib | 16 + examples/name.ib | 4 + examples/pokepeek.ib | 20 + examples/speed.ib | 8 + examples/sub.ib | 11 + examples/test.ib | 16 + src/commands.c | 512 +++++++++++++++ src/edit.c | 204 ++++++ src/hardware/23LC1024.c | 86 +++ src/hardware/23LC1024.h | 33 + src/hardware/LCD2004.h | 162 +++++ src/hardware/file/AT24C256.h | 74 +++ src/hardware/file/file.c | 661 +++++++++++++++++++ src/hardware/file/file.h | 130 ++++ src/hardware/file/i2c.h | 76 +++ src/hardware/hardware.c | 139 ++++ src/hardware/hardware.h | 32 + src/hardware/i2c.c | 73 +++ src/hardware/i2c.h | 34 + src/hardware/keyboard.c | 91 +++ src/idyllic.c | 1162 ++++++++++++++++++++++++++++++++++ src/main.c | 41 ++ src/parsing/evaluator.c | 491 ++++++++++++++ src/parsing/evaluator.h | 71 +++ src/parsing/formula.c | 205 ++++++ src/parsing/journal.c | 91 +++ src/variables/avl.c | 652 +++++++++++++++++++ src/variables/avl.h | 88 +++ src/variables/variables.c | 162 +++++ 35 files changed, 5541 insertions(+) create mode 100755 Makefile create mode 100755 README.md create mode 100755 build/idyll create mode 100755 examples/arrays.ib create mode 100755 examples/err.ib create mode 100755 examples/fibonacci.ib create mode 100755 examples/loop.ib create mode 100755 examples/name.ib create mode 100755 examples/pokepeek.ib create mode 100755 examples/speed.ib create mode 100755 examples/sub.ib create mode 100755 examples/test.ib create mode 100755 src/commands.c create mode 100755 src/edit.c create mode 100755 src/hardware/23LC1024.c create mode 100755 src/hardware/23LC1024.h create mode 100755 src/hardware/LCD2004.h create mode 100755 src/hardware/file/AT24C256.h create mode 100755 src/hardware/file/file.c create mode 100755 src/hardware/file/file.h create mode 100755 src/hardware/file/i2c.h create mode 100755 src/hardware/hardware.c create mode 100755 src/hardware/hardware.h create mode 100755 src/hardware/i2c.c create mode 100755 src/hardware/i2c.h create mode 100755 src/hardware/keyboard.c create mode 100755 src/idyllic.c create mode 100755 src/main.c create mode 100755 src/parsing/evaluator.c create mode 100755 src/parsing/evaluator.h create mode 100755 src/parsing/formula.c create mode 100755 src/parsing/journal.c create mode 100755 src/variables/avl.c create mode 100755 src/variables/avl.h create mode 100755 src/variables/variables.c diff --git a/Makefile b/Makefile new file mode 100755 index 0000000..263f47d --- /dev/null +++ b/Makefile @@ -0,0 +1,2 @@ +make: + gcc src/main.c -o build/idyll -DDESKTOP diff --git a/README.md b/README.md new file mode 100755 index 0000000..8079c08 --- /dev/null +++ b/README.md @@ -0,0 +1,140 @@ +IdyllicBASIC is a variant of BASIC that encapsulates memory management. + +This means two things: 1. Idyllic scripts can be executed from program memory without loading them into RAM. 2. Idyllic scripts can store its variables within external memory devices. This includes anything from an external RAM to even a hard disk drive or an SD card. + +Here is IdyllicBASIC being ran on an ATMega328P microcontroller using a 23LC1024 for external RAM. + +![alt text](https://i.imgur.com/5ZKFANj.png) + +Both of these things make Idyllic ideal for low-memory applications. The ATMega328P microcontroller, for example, has 2 KB of RAM. Normally, this would be not be enough to run BASIC scripts, as you could only fit a few lines of code into RAM. + +However, Idyllic can make use of external RAMs and program memory. The BASIC program does not need to be loaded into RAM to run, and all variables could be stored in an external RAM. The 23LC1024, for example, can store 1 megabit of RAM, which can be used for variable storage with Idyllic. Idyllic stores variables using 32-bit pointers, so it can handle external memory devices up to 4.2 gigabytes. It can easily be recompiled with 64-bit pointers if need be. Idyllic also stores these variables using AVL trees, so lookup times are fast. + +Variables in Idyllic can be declared with the DIM command. +``` +dim myVar +dim $myVar[15] +``` +There are three main data types in Idyllic: 1. Numbers. 2. Strings. 3. Addresses. + +Only numbers and strings can be directly manipulated by the user. Strings begin with a "$" character. Addresses begin "@". Numbers begin with nothing. + +Values can be assigned to variables with the equal sign. +``` +myVar = 5.2 +$myVar = "Hello, World!" +``` +You can also assign values on the same line you declare the variable. +``` +dim myVar = 5.2 +dim $myVar[15] = "Hello, World!" +``` +Strings must be provided a size when declaring them. In the case above, the size of the string is 15. + +Trying to store a string into a string variable larger than it was declared as will result in an out of bounds error. + +You cannot "dim" an address. Addresses are created like so: + +``` +@myAddress +``` +The address automatically gets assigned its value, which depends on where it occurs in the file. + +Addresses can be jumped to using "goto @myAddress". This can be used for looping. +``` +dim x = 0 +@loop + print x + x = x + 1 +if x < 10 then + goto @loop +fi +``` +This will print numbers 0 through 9. + +The IF command can be used for conditional statements. The block of code between IF and FI will get executed only if the condition between IF and "then" is true. + +The format of an IF command is: +``` +if LHS comparator RHS then + ... +fi +``` +Valid comparators are: +``` +>= Greater than or equal to. +<= Less than or equal to. +> Greater than. +< Less than. +!= Not equal to. +``` +Only "==" and "!=" are valid for string comparisons. String comparisons only apply to the first 8 characters of the string. + +Some commands output values. These values can be redirected into a variable using the "=>" symbol. +``` +dim $name[20] +$read => $name +print "Hello, " + $name + "!" +``` +Scripts in their own file can be ran using the "run" command. +``` +run "fibonacci.ib" +``` + +If a number variable is declared with a size, it will become an array. +``` +dim x[10] +x[5] = 12 +x[2] = 8 +print x[5] + x[2] +``` + +Array indices can either be numbers or a variable. + +``` +;Declare the array. +dim myArray[10] + +;Fill the array. +dim i = 1 +@loop1 + myArray[i] = i * 2 + i = i + 1 +if i <= 10 then + goto @loop1 +fi + +;Print out the numbers. +i = 1 +@loop2 + print myArray[i] + i = i + 1 +if i <= 10 then + goto @loop2 +fi +``` +Arrays are 1-indexed. You can also see here that comments begin with a semicolon. + +Assigning a number array a value is valid. The number will simply be placed at the first index of the array. + +``` +dim x[10] +x = 12 +print x[0] +print x +``` + +Strings can also be referenced using an index. This will return that single character at the given index. + +``` +dim $str[10] = "Hello!" +print $str[1] +``` + +You may also assign that character a new value. + +``` +dim $str[10] = "Hello!" +$str[2] = "n" +print $str +``` diff --git a/build/idyll b/build/idyll new file mode 100755 index 0000000000000000000000000000000000000000..cefad128534b854eafa3dc928a805bbd3bede473 GIT binary patch literal 53072 zcmeIbePB~X_BVc8h#-O~NEP2BqTd2iz*i7Z3S0~;1%wt+!BW~3s->-Mg2g2eZL5s| zWmR0(RTmYN1zb_Fq9T?TTSUYPtb(Fct&)%`RS>Ea^81`KGxy%4#dY_)zvubm;VPM# z^EPMBoO!wPayw5SJu*HnPE$`C?K+K9odsm5L@caP6q+_v8=!TFQ$Biq!zB=~CIi4K=ay9{lRC6jUpOnh~cuTJtAp(L-9p|U60g#HbX z_KXc3z|rI2UrmeUntkL>b$ zA8Af)yv*-J_0Uh|r$T8~t#4lLw5zY|o0r`uFE`&)(x+s=)qSqMGP$@Q`Epi)^rAe- zr*0UNuEqPbDuO9~ig(37GArSaUhwI%DQ~anzHLe4-+I`_KeF$tNB*K@5D(GNL-bN5 zPE(wkBGHKQ-^*~>JhhKq+h#K01V8Nn@6rnH(i6a+1>DgJJ+;Huqc|%wKZk^7%`DV%ie0WdH4;Zoe6@DN z=uyLlXI!3qjS;)zN+WuC@>N>KsI=6KY*&$MdTz1XRg{)GJg*?%m6kaz&xI_e&n(E7 zdSwXGRtZtic=&W2ey#tBbX&kEMo%25?nbEE?OD0Gov252bJ!8!aHyo^x_f zCE1T7O^@ndRlimz8^|u%e=7JA37=8LY(_t*(pB#YIJGsQnMiN8z-3p-h*}H$G(pP0 zyDV^3CPLI%;HnKXLlysO)L!F6lz-b-i3Gu^zfey?m533X$2E!QW`T?TLLeL#IPs__ zsY=8MrffuzepU3Vu|6=g@eHUEQKIi)Ks9Zs1>VsDcUs`6P~#bAfuC+bHEogwPHpq# zbJ7AQEpXBTCoOQ&0w*o--?xCXw4uE-V0-UnO>>r4x#J_X&eBcoHyRm5uG#`rL1~)0gnXQSgwizK2o-YrK}yq9B{Y@O_feXrD4}tjzK7B@H3<#nbP=U#Y8L9p z>HYt}g(~o&K+#rS*;D()9jS{oi*k7?S-*6gu&5AU%|mY`?IKX{r3c zr9hx_f$drf1~$19VZON_B=embsk2|`BjSxR1bt_wzp4WTJ&!y6jn4HyT<=`p)W#WC z?fm$-yDJ2wN&)R7bvgD6N0|Hv?HBy&8}d(}HBaw!XX%h$6m|N)b$4_IhP;48uqTQY z%*Ic(?Ion+rXX)4f8r0_4P-ia);NQ4+LVnH^?REGdb4vu;$OjHuWXxOfc=dXdXv2} zy@~Oi{s??U*Y*nq9`2IhZ>rFn?d$Yre@*cFW0A0^5mJ#j@x+cOtfh^aM zzge>Ndz%=&An|%r%vT_E`fc%#$7@Q(fbGztc+xAFMv7a?1aqV|qatJPT{d+Mw8h*qs1(@MSdnx~kGR;~5p5|&oQRipWz0jCM1*88`t`Ecvjtxo&P8=UKd z4*!Pr``h?y*Vo0z)y7rzT<_oFuU+8mNABw1P`V+mB0b`?ud8K2akc&}6|hsie?ydv z^}#lNy`D3E+UGr{xz9NPd$raF!XQypKD4UVk89yO2zXoqVOefp=@GQC<2^Sxvo<&v zj8iO(J!+xffUJ&I#FNxk=n2~lY^8o2R;bXA3&pDTw~MQ-Z5p5-pHpTu0&a~5?Va`d zgZ2dcIPI5J`8SYOer}cv(JW!)$U>6A(#SGKVT31tW8tkrmsoOIj{QItWc8{FpY4RW zkN20>#W_#ipuigr+9y?kDHXX+-i+*1>j`D=tJlv;6vFHYozl@C+izaa+STYy)P|TU zS+Bq6bQQCg?E+ksutm*PYsn#6Jdjx>*t$UELHjL2rm6LB*S$&S|4&OtjS?MOJNE^K z-VaVk>o8K~w;&acTWB>dJVo_kr43wBswdH#7mSPZr=#s#{pV=-VtB(*e@$@YuaO8^ zOshmb?@`V3=|YQSzqdgNPH#YO{-db+Ma}31k)j@v1{0H`A63a7gJ%z@FoNZ8Aj+lG z8zN2d6qAd`51+T$;qHjvQ{AWFw-dT~>eItE?)ZdHD#8v-LLt_wqY@L4xLqYiB5{dI3`AmxN?eA-T$P{_UZ)bI@nDs(R@DTI ztcFK-ZwqJx_{{-i~4Hb~*^uJRAdH&bk_~p_hLDvI;a!O-x zUpM6de1HC7WSO<2VniaTCksfi!F^}dIu}5X1-kF8ek_kC9sg`19m`2H^zcEC3RBI6 zNG`UhxdiEDrkaw=)U>oA$?x4+tsl|Cmq58A0evTHb_AOJ^t00J0Q5P+hC4#B!R==4 zfMy4vS^Zly*_P9xL9Cfxk36L*Fzp+M%3lLT*MPdpT8>VjreQgpj5>-q7uzdG*sAR7 z@P8@_mcAx1{=B#?{%ZfHK_3)BzH(Th7;Lk}+B4Bq5u-e^!E8}KVpZyeBQl#_W;RD; zHi7hdnZ@}nvuHPKn`-fE<-CTTrzW+Vd?;`QfE9tET}zuHo>SH2=v)Sl>k2C@6ut8u=x0e`%;%ZD zo22JqGA!x4QRN8wYneVslSsXJpx#t$7Xt)w`^P1PJ7E@y@j@mkpdQ?g;os8lI~RBp zg7n4}(62;(?h%3XE0IO5$l_BPFlbg6NJkUW(WKJRq%af&(t}8&Nu^VhYDBsT>3&EL zSQuWRYJ=L>W^S*0kb}x%B4<%fuW=%myEqpHI0K6Y01jDIkhR$vD5tkSK%D|w3+OID zNn=1K31}Ul!9aQsC@yVz0Yui6&jFeq^b=IJX@T@*&IOi?n~su{=#0zhb=2u!G=qYe z?8^%Uu0-IXl|W6WR|NDulvB4r`p$rU*}x5+_5ppRU*8!%g~MF|*2%B;0M@TB1G!&c z&8RCGQYHm-L{VUYn&4Ej4T?qaG>)UbZbU>#qRi|llTf-Q*q<=^YJfebl33f03N!<% z<2)M0OB+x{sJ&F#`?QyRrs{kWWS_YT9m5*c83k*ZbyGiLvhjnq4Yub}6i2y3_@&Wc+`oW|O!cm;URTy`NN+HG2=oQA>9r(t6F_Oc-m; z{&K&p*+?EtI@jWHS-4n)1=437(qr^F#zTqM@0p{?5Q6ilX*S2E~;}@Mwpgc-Z(bf35s}Wf{KYVB+k@;{zE1lVrW%dpwF(?NGrrdU?12)Z8drg2u_ z?P2C=bVIwTY-TsJg_ELJTE}tt?(2w%Jjp`TD^Yu-j_a?Cp}JETVV0WUy@b)r0QPj0 z>ew7* z9@Qi{{920q?;XA?y|hF-Jd&8J{N7pV&Ywu(-#;r|%Je}oEA6ev%op&cMU6IKyWSVC zl~;Ls1rqxs1}`Eo&(%3by~br^Dq9zzL+i2e5J+rClnd|{%IjEzkWr03A8ZI3Fw4{e zw$QwI&97sEBZMrV*H|XLem_=b{Q8$UrQRS95yW)w7|g4P7Tgi;G@^m=;n4t+pBPhkYd z>M33`1L>OwZYWL^30e@4Jj=lo(C1UPey#lteLqYeRJhrgO(MM?8Sjsq*N%dSw=1c; zfall3@KYK|!X~PeI|J#PqRf;69Q5VU#du%%4=SY|YtRiS#UQ=jUfLTTfmH^fwY_XK zic6|#b4McxYIAk7F-8qEY6`8!88wBLGi*8T`~aI$Gqj4F{l61AR<>*wIa_G?zZBUW zEzZzViu_*|{0SbnH}&I}M)mf9*TO0|l3aG-r3G3(!qNhkkLqaoNUk9Gyb)eLIV@PoxN|`|tsm9N z{_5dxxse=3@b_t0DI3g>e+vylzAKV(Dg&&+0h!+#~4cH9exZ6OW%iUkw76*K{D4I>nK1icC! zgDBjMl&cyL)heHAeYKe7VTHn2^urJ^C1}k0o*{#v^;l9G zh~*_0xpkxUDsoWr$yPR!cpv9Dd|)UoZXfUAIsab~(&&Sl)I#L8CMy)wJnPY>66Q*J8?Q^N#j1v>DD5)Z3Ba5bujzOh zOL-F}iKK8%IsG5MMH~L>2t*^p7HGhPh@XXajxisLjl{c_3FTtrwr}LRULVoMY58!i zv98w?x21GLKVCf?_En1&wKlUpP>V^ZjiJzQv){7`j=A8abO|S@W8|K;;6Sq$Dyoi{2m&HQ4^_a zFjue^(kPz}#W4TjI+1He0gMb-MJ)BM*4$mNCWr-3-r9x*_UnNsegf2D#k&EHWnEWp!z>>Tghkw71r1t`t$V`Mp~MSEbJ4 z9p@Sz?nP~}zhCh@QIf}l7ZM}itKs(D^9 zTDok6(dDmaPhTI57fx1fd$|awV5)5|QXofSs-R|jrEL*l7@=-L)Q{-k_Uaw#uc&d_&~vcB=IEnrzB1?#mXSE zC>e1=Mun~EF589bXrc25l26^xZ!1?jbba*gerO)<2I%|j z^Dn{Z0(p4TfTy)HiuNVJK+WLB0#V|@x7o|+m>1c`=*hkd{f#|d|E@w0gX=qHc}KET z=z9R$gMv1r11qbtm){F&pLb7^`;YkT>Gt5a@7x>lJ8+(k+D~mHe;PB%Jj2pR0!oAZ zL>2Wy#WB$&KH$>m^M6Bfky*E>Kw+o5j`j)xAMgNU|kW6ko=i|`pqM)J&uMf`yWxXhLJr{a&zVeJO z!1e_S-Hr?GarwMoB)K#2+tYmue*4bFxr8qU&bvaECBZg@H4uk(sK8&Gu)vflt5=Ug z{S`S5z{~plyHF@uoXe`v=8^X(%p7v;bE`0SGP@Y5HBOY@p-?|=Iu2I z9+3pqwnq`e#MkCSNHe0LJ0p>w?6-<09tv8E^cBQ?C5rSFXVVotqBVaG$)AIJ0tQe~ zq|doXpL3Bu=OTU1Mf&^%MbcPS`sboZU$NF-S&CGb_b-a{t|X|oRUt-2dI=#FY32?~ zk*J~%9mFX%QPESe5hg175K6b7onyZbD>e2qnhC*+!{q;v1bQenaD%%LW!;acsDHws zLmQmrxeV|y1Tg%UJ0-lQrz;C4pV*HWQNWjwMV#kSDZaB3ACDftGkQ>nv^7HlTLH9R z_V#p@icg|e*I91}ZAT%2>0@9fE6f^!>1AMUQJAL%rmyE}>JaS7dgDFaRLsLi=7em_ zkkO{uP`4}IX@Yl%Cz&zK%xCcqQPjg@;pY=D7Pd9UgHW>Ixz2NwkS0zKQoK=|BwW8^ zzrXh1IyFZ{{}hWLDEi>v5c~CiAl4_uUgDW_B5nP(Z^0?FBR~EJ(rM)eO3(46wl4kD zf8P!tK^KU;)boedMPBr8iww_$yxUJCum8UUHzp z#heuf4y%IqW8b4f53ww9a2K+8Hko)cn9)bx23$y-?+nT%8H40XlHW0*HSV(o_Y~kn zi{8sx?`7IptsACWwf+(*q4i$Y8ay^T#0}8*&RI+R6*jsnf!-v@UCBQ{4@K2kPhOh| zF2>?&Sgid7N8=40GCly^;5MExUnUJcfRf9pr?*+ozs1`azX@Fp6Vsb7PA}smv28hP z*ft)Afob81*MYjLGkx8llzQ{R&^JgA7OiJ3gnU|G8$kWWR;t>qqGA93gRt<5t@m`N zU(b0K0nkdF8@g;e%6bM~mIc-K~M>s&HgZV*|E7pbQ|j>&j}nX$9AjDK+b zR>qB6Tgezp+Dp*3{qN*qYT|#LcC)C~=v+9RX2(1m|C;f3^$BFtVDS+`IpN=gsPge* z#Nj$g)%sB!b+_?&b~I2qaeS>_Q1U$$B+?c;N zYwin9%yJzUmhPF*94$>Mn*=Cv+RH8wB9HUR|3X^MTS#^LDHc(%R#NJ%i{M2QG+HQ! zY*DE%96Z!>CcQ4#1dn318-eXOw(_>4tAUAi*=QrFh1MTu39T!5A}ba4c^jwL%Wnm}&wG%TkWm~hG+yX; z5Y{VWVX*2?ntQxc?4*$;ujEx?F!0r_i@;z(7Jf%&-c#z`W0*NYJFWZ%^I4eY*tk2O zAENiPA2r-?GUeX6g;)=vLt{-ggROMtA#A8o&G-*QA_Mh9MIF|l(zMVDl9_&paGwC% z3-v}5IPUIe;sjFoEWtJdIU0yGAgIN_MUyb?s!V(u(-{~tB1ae)4ieUFcP`HHr|GLg z3y>3NdwOP|KE!0-{>BJ>)ndQCi`aN#7Af`ainv{9e&ZlbHb0#N%OU1aCO5y{phz|; zF1Ao?7Zm-%7a|{O3SGF8-B_=X+2+(BTdF8Hc=n-n)# zC=O5M()R~NKa=7T3&l=B(GwJ>n-py<6t4=3Ug5Ez*^h)Q&0a)hX*xYbaq3mNwnxz` zZ5vIpH5Rhz7P7d7X6uFhjt=66YQOIbybW+CG#Sv?Ze$^L9>k3v!@n;?EkF`=Be-f+ zk7`(r7J^_MP6m-95@;{h)D1`c06QDd@j_F_uBMKO8#4@tIfke#>`#cQs(VIIP{n+1 zQq)=~<_QWi>YD=W=h9W%{*EM0;_>N*@K6l?Shcu`NO(c!7#u6ZeF@m^159Rpw~#>d zkWQB}DchNjAb?+(t>|^|j4=rlkKN9t(0Gnut~t-}d!O`s7So_jNBFDt?=gTSf={cl zolXIs8e4-0mn`vAL(fncZ5>@2*0GkDn6psHrhJcsB;q&h8 zP7ML+$Eqsy?>Sa}2g_oXPnpGonL$7T=w$M03}X)SuNq!eTOOQxwB#V9aD_z+Kj03l)Dkf*ncrLB_XU2c9}r?qDlLt zh4w~4d##{dB7FE)Oe;hEgzi;hpd?A#shh6}?jdX!*4$b@nIskS2^uB85Uqm_MO5fm z9NdRG{|^7Yg^BAOp+~8YTBkP*)EBEE@}RH;wVEq1FA_uKcQiy2sG31ML{jp-57ZF( zEy*F!s{(X3Y_v~S-#%4+^{Boj(ayAbvQV}Ht3Z`}cmsO+y!99yvv_daXAF+F2+gpH zi9-cTP;uXB?$M~JB~(-AW1o)tUNJ1vORvIA-b;13v(&rOs6#u@V#~N1Yvy8142CcA zdB4@%ofY4$8;LKd2E@-{$RlQcYJ%?*O3ps^!zB!(eDV`#)5{`zHynyy>bQ?I-#G9pMLSv8GqcS1 zOE7bBU<&W3(GQ`JTIgPKMog?L^n<*~cSv@Q^$<#pkFIozvjER*=2nC~2b#NG+CJaEhX1rJ=g>0yI;Co6uEm~RdJwxA$>Y!r=|76kj^6e%l{e8;KUQTbI zQUQmgS_u#Y54D#)D`My$9ui~+A*_PQR5!2-TF}&(Ce(c4crvabft8-cWs=M-3~ zPxx~D_72mUAIaY=SU%)4r3mFtRDv0-W~_$7fEg?(p*AgR&#HA`EuAn zZ zABDd1;KrS}^VyHy`Hv=h94se{h3I3+o--gMnGg^qX|E?oB(sSsvENsGjN0n4-gI&E zSP~H*>!XNqH87&NTR$EW?dK)(R3vN(ZoS5z%N2z|Psk+pqNC-Sn zCU{~VdQea z0=6W;=-zSSg@|wkZ%b2E775>j+}Z%axg7%nx%I8F9Y9Rv_Til>x4jZpZL6c0$m1f! zP`2)#E)euS;AK@b2ehq2G+{`-5pAitzc$FHX_1`6q(|}*lusR79$mTL~;5R z=Kzxv)+nG9HbAQ4@HGfqHd5FK=`1x&78)+Wf!9`)eE2O=@+z=!6$KZezX;C>*e(VH zUq=}eu$_+>tKAimK;jR%Soxy+pC90;1I8cnRnM6)FOd3F>7L)KdsT_0aYI)m5zW za#LlpYq+aW`DsWem61Yyi}yFoOZxe}>Pmk#P6G(qBG!cV^N)rT<##xs;B6*YX4#Fi z^y~>=2gQGtbMs%}Qv7Olv;xh+WIxYj_j!L!m@6mNyuT_+@cz5pDC|=DH=J}YMe=9mma)w3G~f!Jzn`6Uh%H_Aw#79j``(GgNcC`V-Ey9Z&PaP6aN(${iN3O1+07 za1eYir6%}~-87rtgH9StWLo%q_Q3F&f%HAZB-W8PeJWkqurPTA_1AJJM1KuaCK$R$ zs7Tz61N_TaRU|B3aX(SHj@0 zH@&1rZlf9P!MJcQQ|pIa83-O#tI7T0npTEW; zOLTfviEf7y646Z{FsI&6O9NE;6%68~0ZJ}McZVW_0*7q`#h(R;X7XX#{ourn=zgdc zpEt|%)M#sYuoxib0AXV>U^`kh#D=-6c^(sv{bDiTc`|o`Sf-a1@ghiJWX6pBh>RSy z7*GMUSPXa*yBT6Jpn>ch5{m)Mm--s2b^`2HKMDw|cX1!Dk)mQSP+ z-WExz+i4`oX!tLhB2XSsXlz>eY?G$cq$$N69x2r&q|(CpDwq^Dn8gr#*;4T1 zV+%M~%Bv6O{3tzzecXb)Bux5#NRWmx!>`wc+tuiGLF9ys&}3Ah z_k&n|sL;1@8OI9x9-z0B5&OXKwDfIMGRWHoiA7Ml#`fM+H4pxL6le^Q*Fa>b4|D0; z0-Y`e5~GfJeDtzcacx%L6UQ44Ah5*}oF)l`hCx_>HQc6owqYk{pk8M$rM(ALPJ8(& zloDGx*p?Av+xMvdFfOD$2}HjLEWp?1J_XbnbJL11X*vCiNS_YM@Y~mh^JusuQcph~VussE7^r?`V;G+;zp?^qo0eMf6 zjWeN^^gjgUfI6fuF?c~7&cugmsD{J6@!^bsZ9GJ&Q{5wh$A`!Qsk@YWOxQtM?!w#N zu0i^qq7Px9L3$k~CaIVi9OC0E>_)vo7nZ}i_-KzY4@rm`RUbxnVuv7V0#agvWjAnD zCHFO|_a7^gYE&J{Nm_G{=sX*7soBUUD4N;DI9kX(#pE2rocW5A_E}BN??xJmN{zO@ z&h3}-9KlnPY&G3*nQSkcY}Ouiu?d#a(pj1@x)q3|D&JI*S1T4xxjAKGN_t8fohHCC z$6Bh&8hxt>*qLf{`uYV%#Wx()dJX=)N5ji|eEK87(4#s`TjTHXqTPE2zEM}Dt_G|c z4))S&qaG+(Ba)jWc8y3TiJ9Qo_T2f!3jJ#fp_7;mZ^j~zqG+L6Q9^&khdEo(bYu&m zZ3LSVdcG<2J-@y-+`Sbcai)+`+~|<%y!9Gav=X$FlkO^seNQB1ktesV-Les}c613g zC3K!hDmxa6q#R1y38B>$`Wvk%J-UVL%cHp8$DB;++KBEKLk?EXbqK3zMOXxDxS~C( z3jbE{C`DfqNm<;PB)g^CyxBs^EM{Z(CbwBAl2lw&#+p_u!)*#F#Z41gggzqwzA|}( z5LDHw_g-#FkmLu@4P(Zl3UjKd25I#xW2qOZc2i$aorb=kBic@=oaTou%lYxJSZlpu zikQJ7oJz#7)>7>`0jtrk^n1u^=!0oP@6S(M2+v;H?gQY|PCrhIra8@$0KBneNAy ziz)6o7H4R*^RrlS_Zi}L?o#4b`n+#k=lLI>x5nYQh>n-7!bc=m+W%Zt+89@cV%6 z^r?)aorTxq?B(cE@lK5u#f{baiuP!SD=@}5v+&X9{c)IUEupA?Q6WvMYWTJ^N~Q_m zQ~{iUfPstOqQ7gwjB&MZQk-WT&LclM@2pC2_S{7IlvW`-Z1crtv=A~!`9Dda?IV&u z%D*$^9ghDSVk@fkO&CcxT0QTfqCC*JG!nr=>;U$a z@YSHa=meB*ru3XHC_9QZA)C{`CoF!}&>t^xE^zI-EoE}bl$6_3GK|Ya<1DK+blVU+ zBXS9R8B$#Q#1WRNOw_qL}&732WN|BpIQYx}u^yaND1XY=n&|YRHCtf(JvMwCa z*V0Y?{exml_~LTzJI|E`UN4d~6~4`lJ-Wyc4>drsh=lei&zwx)#cYfU=-;$ZTcJGd zbaz;Td4v|CE?v?3uz-hmFpOIu(?XvDg}pBP`v(6GVT#)bFjX=R1@dnLWo|F0?gvEJ z7~{nt%R*2OvlP~aARFtBe9$hnPyzChg|Z6-mU+TzE#g^GPC7p8->q4)i&Eb3= z9TIt+)`gnhwGL)~r#@F=uE82#%t44k@aO~g$b61o3SjavE3(<%Eya2NqeYR?vojbOBwJh82fPC zz1~Jz?wHkK4gG4LHu>rZ>816tvYtD!3Vm}q1$>>SS7$0$`EtBw> z1PUbn(}BB?@^i)ss8u2tx4-DDt6m?*HTin<9O+O^EUweHVd@8A>FPW4)tYv^(wqFW z#eJD51I}$k!e^rjEvU{WN)~V13sJ=jisbuX!=Y3b_r*1oZ@dE_Xz>xJ5-7#ncgSz8 zB=C6;33sX@2YrGEkR#zvJpKj)A_==3kt+l8bM?-E9^@}o(7on5@y!YxZ_vUybWR1U zRkS0~%=gESW0$bIg7oB%o&Z7@Dk9hF$MG_b3f98okv_(+wa0KKKm8bGAg+bOAPOQs zYR?xGaHatDcU<#4g!ixV(73RBPz<3x#4P<{0)j(1(I$~kB1AO0(Vu$)8 zjgp6CClpeh(0-id?#Mk0)8fri3)w(xD%O0Jp|4czO^nQ#DN_eUitXT}y(}MM01BZ) zDr1?NSWLq*X3q`&MGl}tbbiMa{Y(qdw+qoQ`2NfI{hu-@VxYSQ!m$btasJ2H0M+`} zap3_V_Em;44?OFbSf~Xyk94?-0~dR#a`AAB-Q#?)FsE+AEI*{B#iBq@mA z#)^8*L_rkUf9kVQ9)FKWzAv$NiliI?rk+j%d!5F|3k7I2Q8!)Bb2ICZ`8|Z3%Z(QhQ;Y)kb3WO&@3rZ+YowAqTpS@e~_Jq%U zmnEJl+9YV~m1Q+$PyCXBlMQ{X%5+vd-{Fw5)hA zaBp=pXIFlfDBFa+u@^xVeF56^>I^E@rM z8y8DtXd?19E%xD=hQ(Glv0*1#t<@96_DW@~{w<0YhD9p$7k%CrMbTai9f2{{VC7Z| zeNQo-nSXTL9 zo5kDd&xYU@;N05q`6v9-A>=?fTgN+rp9XioiMd+=W$ein!rMyW?P7#~PQrJAd)L1Z z&VG6NQ`By3$6*%gKZ>7J)qgVe9e@+-LvAbFp-~4M4kEs#H#f#@NWx@2eov{goG$#ly}K`dyYmT+&v8QI ze^6mK%>9M`W4^A7oVGi&w&VQN1X2=*%pJt!IS1cuz`ZXayB%bc27Ht13jy1*i1Pz+ z2haT0)N3QvYYn&WGA>pJF?;>+3-lBpp*Iqe3t94K;Z7o%DU$fiLI=K~?lM&9%YEME zFe!?&Jk*^f?LGrd0pq9^>Vh;7yX82#TaBZC$MlfC?kq}j!zU!??>_I}@i8`3{%)S? z5uQrJUx9{eKJ%DtWV9j|BGoL&4}h$;odNS{!gf!hLlV;W02S_9Z9Ci>TaE!+0|H2! zqwt}8AxRD(oiJKRqisDXj22KvlRdx?FjQkVvxT900MVl7+rZ<*Yd-I5!bq=$j$vuW z=iOx(>3gJMq+QZTyOfb$g^_9vBX$2L8R=D@_f=t}U2G)6lN~6e_B-cMtC1dsWDD{I zAcal3!X|!wrAWN}NF>r*UrBFXwr#!exrqg~j+m;GxNM9D_?R$F8*75EAOYMjus`9P zNaD|qpfa>@PjUX^0c232uRs;92y`liD14w>{*j6jWKxPRa)EG=zOv|}Kw=i*^_6k8 z>Pu|tAc6d6rTifJH=*D;O7GAHtkR%BvaaSaC3i)RpF~}CjH#Epmy|=#0kB0q zjlu!Y3jJ-L_iZs;yd6phnNVQVdbIPtw)bF_;&yyDJbVEbs5`9&0Ds(RJ%gOQN(^iG zoc+0{|DAszsxxgTU_9vyACTk8Q54-APd>yN1ip2L!)5fs4$FV|8a(=3d@`4N@X;WK z*-G#}M%D5P`Xtsmv|VkbbM&1A5RKJP}& zjoYF6#!wHC`Mf*2x^Z1n-yz+3hjQl)aOYKqJ5Sh7+#7t}4VvczvEaOeJ(@^JZ3?M8 z?uX0|pRA2F)OHlsG}KaBJW5|{8fxjQ!cc43P#1$3h8l~Wi3C@m{}hJ8mrE>$x`y#= zs4cj)iz#HXwX?h)#5J}DFGYZ-##Sa{LKL0dHf{bB&A-KLbRLVcmmMPqu}m`?Q3u8> zMmZ>5m1<${Wmvtb&~XrLi*V2_q17N04%!4G;q^+LD*CH|cz7LF-uR0p`X)A>ZhF}w z7{D~%bjlO^1vSA+2t%b|o`Szz)~gOPiLXtQ-h@5BaDPF#z##k{gh3GEA3j*|7J3&L z`a7C(L*9i*3hT5%9;S76GoB5d`GfGtFNAg4sL2-J%Td!xWgXg1Xue7_4l-e#2eCFOjj$EA?#5GkEZm^G*1|=BMM*rfpM+nY**!naoJ*K!<4^h?EWCfD5sYpzXKA z+4K>BUnxC`)47!Xh0@ql#;=RgO_ZL%>0(MB!SabJO5?>w38RIu(2>lPV+h4AGpOQ0-r*qOhSL_1N#X(cK z30CFsXXVl@SzKey;&3Xxh#j73NDcmpGf~E|7>kWDjP;%-^hWj5@;_D7P@xR1gHiGW zmSQiv1OADVn?e&zp+H@SrU&;?e-h6)vL!#XDcaMQ z&D5Tc(@}D)jK+CnGb^emFz#Le81J!*x!&{J1#mimZ9F)%7=)f3Y6WmSFRV)T75fDc zFVDx@Dw*f;o_-{p1fWd;U*9b#aeM4|dk_9_6v^!NF$2*jnD;NtzZzTGlxTl|mJ#qR zDDy*)RWN;^Z9JcYT8%gsg(G$F&N@tusdtQf7?b=k%mLVL3Hu%$Yv@w}qxnD4?Izep z0oyEL?-7g^Z@{}r!d@X5eS;FPbrSXz!5$E>HzdptSa=qQ=(UzIC?S9gfVU)IIswuE zsFZ+-1Q-s$s}i6S;Bo+7k$@`+a1j76OTfhhNC05D1atww^2yVwe(y@uafeoRR;%?& zErbIjXo_^MezNz3k6kb+>HKGdr0J+HA{`kv$HV@r0JzzLF!WP+;#wf}1h1yuJL^ZrEXuEoFrSeDz zPkT}mRYotrN8~(@{w`f0btSgC;w{y+^M#NLB~v?W75@Gv_m+QX*ag0(t!$9!}1nufz^Z z2YcCSR0=OYW21$8Gow=6*c7wPk<5i)UUNALjL{mu>e>eV5oq<-n33aLtc79#kw+!% z{0<{}qvWINBgOP*Mf~3RPQS-j>YX3&xyu>ADs5?1duM?4|EQd0{7)2^{>C(&z(N6q z0iP>HKxF)PSVypgfC^O;%L3c`LRRoE53-3ql*tE?q|Q|^ zB!U6GEv^EiYm*g9b3n3C`tb^U>If#xR)z>*~_NU%QuhVPS8QRwfvNBsqN z08c(AEpP%0#A!6gFrQ1Zv?A>;Pp(@lEXvJyYtswd1^6lUOw)3TTrSNqZMNH0?4WpZ z2dzhuD>GXw^5koI1&EBsPj3Enhol0*h=P2g%gHM!DAGD;voiBME-fq1m06?}x?Fc^ zg#~xIvXf?r|nRTbsRmq)MknMsAhc-nbHyw#YT=+K|{}$li zGx$e;-|T(-BRu{4Ovb|qn`NB-RO$s1ujnZ3i+_$xw<9k%-{sI?N~O3yW&~2K+|)~o zrY&Py80x93(y@q z5$;1c1L4{CgCF5ogv$_?Al!`buLy$(zeLy`Z?h?w?<66-3!xL?#hB~NK-dLc>3oE1 z5w1dbK05!M2=7IB2w^?Ku9%<|Vd%ROVP_1dX_Q9jMmQRiw#5i9T^Nb1MR*q82x

z9xEzsF{hn_um{2ipFq9{pTjP~41~)ORv_&ER3x$z;e}5}B3lu@i?9JbuMkAbsun^%6gbNW~js4Em2;V}u6Jd93sWu^;kFXmm{UE{t2urb3J_+Gb zge3?sTnfDrUWsrG!e0^YLfH3t@FU!dup1VFXTJ=7gv$|5Lbw`X3BnGmz>lyV;aY@K zUO~ALCa=L76;>}MVnLt>!t1Ickr4<#Ss#gHBV4};13SWN--|?+BK!g2CWPZ^B9VH8 z?#-|p)`oU{1b&3Q@Ln+j;bqv5D@6FyUX&Z*(mK=^!h3&0xe*4ijDHAW%3;(OmZ|2U zja`YbH%8Mmgc%6k2fv~YAgOO6aOUeF5r``_*@ge7WiV|PeW+fx6LVWL_zxP0sM9^`fw|M{Ad{!kcAnkMU?T@DD}d{RV#$@K={bB7cj* zKVjgVz`qWBl#cO}8Senk4B!s~|C!a7P|h|VvO8%+Gaoc7F{b?%%_`7L!}#_i>dx>f zl2adVt7te)2rt>z(0Vvkq6bQm$TqDyaY5}(EMPfkq$(8Q~`e@ zR`i!d;s0vrSO@$Ez>kT-k23HY<^jI||8x}oF9zNL{M{JmbE5E>jCTMw6!>?5cUkdN z21`Gk4VvSinPR1hpJd1=1Afq-V|n1)Ac$$+< zwBqB%fam~hKJa${|Ctp}byzE85X~ykI52;k9ZMscF6+4yG<1sfW7M}Zw%=>~-ZTlOeZ4Utcr`Iq~wDxCh9yP|sNxaDbFWua}eo{dd;(E+Vnv6z3Nadav04ZweaeRm@->WgbT8+mL7 z&GYr}J&bb(O&ePqRh}U55ATaaDuFie@vj*C?J-HcBp8WY7ggSYhP{%2A0EQ{OjLco zXw;_@_>aPvms{mqd~ycx-vB=*O8zL8Pb?>&lNLB>fs+ zfs+>af87Fg^v;K8i45uWiJrSfK-)3mNe}_HN%*Nmz^r5}ux;Y1nc$Z(bn@0a1@GJHXXl`^cB;U_Zu zPKGMK8C4<%dqr*-KKxoo(g@eI+{}DO|I3pvPwv;J|CK#uRB^N(lAYUXKSpA)RBv&> z%#nt6NCNtzY-{uv0FEP^T0hxNB)R60@ToEIDX=O0e1#P4O}hhXN?tbUYA641j7Z)`a9_a zaF3Lelq9Hm{{zu732!Gm3RygD0pJd+U>T=9K`Pgl6ai5E-d*rl2kbVrDw>JDwngRA z=<6YPR6j*urYAXLr5#pDwhtvdQ+D9}Bz%X2pFT+dc>NR6uNW?gEWuBbevj<}g-fhiOVpzh{-pF1-UkEjX$jwwEC?Tv^rW^ds)UH(ZAt$XFZ$!mg~Vr44hs-%D9d_ldk<7w@4${*zMvV^Y4-^La@>OA5O|sHM@hkk;gH0o);Jtif(6 zzamEeuO<9Yj6d&Z`F5@F79oZAClLKb!t-T)-6S(<1IOqbf3`NGN&;k%065j}?c)W2 z_hAq{U&0SwF5p>`{t^k_nIZtv9ku=vzCt=O?+<|FTEIKwKW(9)N0OgWlD;WZq&B)qNk|A!>~4hcUl#}`#EUrP8$sZUQyzmMTEVF`Yb^k>M9K~|3z5BrfmfAb4s z-lsvdgM@!Z6COM>M4)w%@J&Smzk{eD>V4uez{x)DDk(q)1EidJ^96wS zcMu&S;pa*N_mK3XB)mY{L6vt5;FPaJ=IfC3w@Lbel3vvp{S{a$@8Jo8koOr8{iB4p zJyXE>><*%S34dG4k#3~@Ny2+e`>Xe(ze@NJId91p;>{DwWiPP6Tlyo za{6B`1iPgCMJ4yKH zJOSXnVnolE@QJehO1IE1k?@eLU-h2d2XL~_FEQitb%3kBOJ>QzlD5z%z9Tj6sOJ_b z{|~aG;(cyVGF5$~%gWxkn;CTpe(toI| zU+ET_HX*CX-9NcN%gD%_mYd-?Dpj3Bxh;at|HfToFjJ?Ww>W%WZ_h_s~D8o z1sT)x3Z`Y|Wn{Yxii$HbJtZ2Q8P9XMUD?U~TBpd!$<5Er$Sf+#oSlKw=0&q{P#!1N zGqOE1XU+zTC6xh6cNFQ&%-nqFlaVoUd`haGfkWLH8Cu4OTgIfMjv5Z|4P(+Xbf?5R zM~v4pZWujwSjy;(u_H%L(9<%~QihGzGc^{SFAk^-|1dUv{1}vE^w=A;I|@8S`KXD)fLGeMP`v})bxCqba-a5OJg^HiHq`FrcFq%yNhz&F5(e& z!*#-zNu&D|9E&bURzczH32xlJm=4<&jK;zLVenc}#}m@VXN(&=!L$xtqTn2;l)1%Y z3tdI93^JQ`cR^8hT7eLxc?wZRm(!IyeFpABM#Y`4s0mgf{Xxni;|xO6ODG|xapt4s^#Enh0gam#^#T3&B`U)yIpyCQLGsm z(`OdsOOKPTP9~r#L3?4hnBbXKRN!&LROIe6T{E)^sp(}G7i7%99S*pe@N8K^y0wym zGQbRaNnueM-5R0hK(>anjzwm;$CBYGc4aeM$2AaCJh{)0sw- zGW^z4JVUx2WyN(w0u-LQ0*w@*D;!4g(Su}bWUTR2Q*5n52x6znEl$ZRoRLXFh;KNW zrj}C-2Z%BkXM}RH;^PX6nU>s-3OHQeY2p52OnPd@u=J55VW?@v#j@_GNh_8KbR8zQ z_~r?k)g^?>j>Lr@p+D&{vZ!FDVF6tB$#ff@C$$y^V4b-e;u4VwsrXTTK6=y`UFcPS zHXCIfDmIEH^vXtOi_VJbj4O~EZ4`M935YTd3803;?ymEFBQi@0?gCBEr@KOIB}=c! zwJf_Q($XkoMh31CWepsdQJj^TZ?@lSs9(x$ktfv|T`n4%6Qv+m!)RPU;=ar588}9Y zNw>YxMc#~VQw|V@gRqx~?o|zFQJpKCR=L6mS5{so`i5Lwev)=%mB<{bdeQHS2A`3U zRgy_P8ZKbn6WtS%TEh$SvvWxjG|Vm5$Bx$WU3ZHbmF-+81_9X&=7O@XY01U2XSy?| zA#@jsaE6NI=3_uE)RJ-8%9T7l-;-Qegc>Yz&$fW3d2;iz`{ZUzP|C1TeQ0cF@)??1V^O1!J(F_=a)?Z8ow?*Q!0ahfaF)9132rW-p>_`-nXp$lO(?idniH~VmcZ1(0aO+ zU#;h>&=Ey#uKOu4y=LLsPk}1G+J{o1${*8heq!~{1eE5+ieK$hsc@Bifgl|zs`%yf zR?7v9imdq6zLyI30cU-rI0JMSVzj5E_|-m=3S;$GbSj(+e%hl_X|+$K!l5#!Sp6kf zqisN{6UDz-8cKy#k}%eOs{DVJ{KF)j+ILf-Ll&6$i6_>6&j3awO1|-)A>TLDdnrix ziS?f+0k!fwB%cavC7%k^Ym5qCjNxyT2o)-Q6~9WWa8(RHUQWa#!w=^uP7$hn6|@o& ztNv^6-3u-cadMJ&Bat1t*MyM+{D;6xzNhk6`(kyHzm6&g z549h9RKCiND*z)B#a|`&sjFTlYE4TLf$^*ORd@^-E5F+34odzKgHuElp9<+uv|0J5 zRtdVP-W&T6SIq=YODXkkR{Z;=%?L+B~sPXJtC!%ye*ZQb@6^xo`Yy5@Pg5sPQhM1)G F{{iu13E}_% literal 0 HcmV?d00001 diff --git a/examples/arrays.ib b/examples/arrays.ib new file mode 100755 index 0000000..a461be4 --- /dev/null +++ b/examples/arrays.ib @@ -0,0 +1,20 @@ +;Declare the array. +dim myArray[10] + +;Fill the array. +dim i = 1 +@loop1 + myArray[i] = i * 2 + i = i + 1 +if i <= 10 then + goto @loop1 +end + +;Print out the numbers. +i = 1 +@loop2 + print myArray[i] + i = i + 1 +if i <= 10 then + goto @loop2 +end diff --git a/examples/err.ib b/examples/err.ib new file mode 100755 index 0000000..ba36a81 --- /dev/null +++ b/examples/err.ib @@ -0,0 +1,17 @@ +clear +dim tmp = 0 +dim pfib = 1 +dim fib = 1 +dim $out[100] = "1, 1" + +@loop + tmp = fib + fib = pfib + fib + pfib = tmp5 + $out = $out + ", " + fib + +if pfib <= 1000 then + goto @loop +fi + +print $out diff --git a/examples/fibonacci.ib b/examples/fibonacci.ib new file mode 100755 index 0000000..45b4e78 --- /dev/null +++ b/examples/fibonacci.ib @@ -0,0 +1,17 @@ +clear +dim tmp = 0 +dim pfib = 1 +dim fib = 1 +dim $out = "1, 1" + +@loop + tmp = fib + fib = pfib + fib + pfib = tmp + $out = $out + ", " + fib + +if pfib <= 1000 then + goto @loop +end + +print $out diff --git a/examples/loop.ib b/examples/loop.ib new file mode 100755 index 0000000..07c7393 --- /dev/null +++ b/examples/loop.ib @@ -0,0 +1,16 @@ +dim i = 0 +dim j = 0 + +@loop1 + j = 0 + @loop2 + print i + ", " + j + + j = j + 1 + if j < 10 then + goto @loop2 + end +i = i + 1 +if i < 10 then + goto @loop1 +end diff --git a/examples/name.ib b/examples/name.ib new file mode 100755 index 0000000..01aa73f --- /dev/null +++ b/examples/name.ib @@ -0,0 +1,4 @@ +dim $name +print "What is your name?" +$read => $name +print "Hello, " + $name + "!" diff --git a/examples/pokepeek.ib b/examples/pokepeek.ib new file mode 100755 index 0000000..7869558 --- /dev/null +++ b/examples/pokepeek.ib @@ -0,0 +1,20 @@ +;Store 10 numbers in RAM. +dim i = 0 +dim storage = 10000 +@loop1 + poke storage + i, i + i = i + 1 +if i < 10 then + goto @loop1 +end + +;Print out the numbers. +dim num +i = 0 +@loop2 + peek storage + i => num + print num + i = i + 1 +if i < 10 then + goto @loop2 +end diff --git a/examples/speed.ib b/examples/speed.ib new file mode 100755 index 0000000..2539a36 --- /dev/null +++ b/examples/speed.ib @@ -0,0 +1,8 @@ +clear +dim num = 0 +@loop + print num + num = num + 1 +if num < 10000 then + goto @loop +end diff --git a/examples/sub.ib b/examples/sub.ib new file mode 100755 index 0000000..6792a89 --- /dev/null +++ b/examples/sub.ib @@ -0,0 +1,11 @@ +dim skip = 0 +sub @routine + print "Routine Called." +end + +@main + print 1 + gosub @routine + print 2 + gosub @routine + print 3 diff --git a/examples/test.ib b/examples/test.ib new file mode 100755 index 0000000..f8463b7 --- /dev/null +++ b/examples/test.ib @@ -0,0 +1,16 @@ +print "I'm thinking of a number 1 - 100..." +dim num = 28 +dim $guess +dim guess +@loop +$read => $guess +value $guess => guess +if guess > num then +print "too high!" +goto @loop +end +if guess < num then +print "too low!" +goto @loop +end +print "You got it!" diff --git a/src/commands.c b/src/commands.c new file mode 100755 index 0000000..08d7e42 --- /dev/null +++ b/src/commands.c @@ -0,0 +1,512 @@ + +#ifdef DESKTOP +//Quit command. +if (compareIgnoreCase(command, "quit")) { + return ERROR_HALTING; +} +#endif + +if (compareIgnoreCase(command, "print")) { + //Verify number of arguments. + if (arg != 2) + return ERROR_ARGUMENT_COUNT; + if (argsType[1] == TYPE_NUM) { + char err = copyFormulaIntoEvalBuff(argsStart[1], argsSize[1]); + if (err != 0) return err; + float ans = evaluateFormula(); + printFloat(ans); + writeChar('\n'); + } else { + char err = copyStringIntoEvalBuff(argsStart[1], argsSize[1]); + if (err != 0) return err; + char c; + bool isEscape = false; + while (c = readCharFromEvalBuff()) { + if (c == '\\' && !isEscape) { + isEscape = true; + continue; + } else if (isEscape) { + if (c == 'n' || c == 'N') + writeChar('\n'); + if (c == '\\') + writeChar('\\'); + isEscape = false; + } else { + writeChar(c); + } + } + writeChar('\n'); + } + return 0; +} + +//GOTO Command. +if (compareIgnoreCase(command, "goto")) { + //Verify number of arguments. + if (arg != 2) + return ERROR_ARGUMENT_COUNT; + + if (argsType[1] == TYPE_NUM) { + char err = copyFormulaIntoEvalBuff(argsStart[1], argsSize[1]); + if (err != 0) return err; + return ERROR_CHANGE_ADDRESS; + } else { + return ERROR_INVALID_TYPE; + } + + return 0; +} + +//GOSUB Command. +if (compareIgnoreCase(command, "gosub")) { + //Verify number of arguments. + if (arg != 2) + return ERROR_ARGUMENT_COUNT; + + if (argsType[1] == TYPE_NUM) { + char err = copyFormulaIntoEvalBuff(argsStart[1], argsSize[1]); + if (err != 0) return err; + return ERROR_CHANGE_ADDRESS_CALL; + } else { + return ERROR_INVALID_TYPE; + } + + return 0; +} + +//FREE RAM Command. +if (compareIgnoreCase(command, "free")) { + + //Verify number of arguments. + if (arg != 1) + return ERROR_ARGUMENT_COUNT; + + //Needs output. + if (hasArrow) { + if (!isAlpha(outputKey[0])) + return ERROR_INVALID_TYPE; + writeNum(outputAddress, sizeRAM() - AVL_END); + } else { + //No output? Just print it. + if (!hasArrow) { + printFloat(sizeRAM() - AVL_END); + printString(" bytes free.\n"); + return 0; + } + } + + return 0; +} + +//Reads a line of text from the user. +if (compareIgnoreCase(command, "$read")) { + //Needs output. + if (hasArrow) { + char pos = 0; + for (char i = 0; i < KEY_SIZE && outputKey[pos] != 0; i++) { + LINE_BUFF[pos++] = outputKey[i]; + } + LINE_BUFF[pos++] = '='; + LINE_BUFF[pos++] = '\"'; + char c = readChar(); + while (c != '\n') { + if (c != (char)-1 && c != 0 && c != 0x08) { + LINE_BUFF[pos++] = c == '\"' ? '\'' : c; + } else if (c == 0x08 && pos != 0) { + backspace(); + pos--; + } + c = readChar(); + } + LINE_BUFF[pos++] = '\"'; + LINE_BUFF[pos++] = '\n'; + return evalAssignment(NULL); + + } else { + char c; + c = readChar(); + while (c != '\n') { + c = readChar(); + } + } + + return 0; +} + +#ifdef DESKTOP +//Runs a file. +if (compareIgnoreCase(command, "run")) { + if (arg != 2 && arg != 1) + return ERROR_ARGUMENT_COUNT; + + if (arg == 2) { + if (argsType[1] != TYPE_STR) + return ERROR_INVALID_TYPE; + char fileName[20]; + char fPos = 0; + char err = copyStringIntoEvalBuff(argsStart[1], argsSize[1]); + if (err != 0) return err; + char c; + while (c = readCharFromEvalBuff()) { + if (fPos == 19) + return ERROR_INVALID_OPTION; + fileName[fPos++] = c; + } + fileName[fPos] = 0; + + if (!fileExistsOnDevice(fileName)) + return ERROR_FILE_NOT_FOUND; + + openFileOnDevice(fileName); + PROGRAM_IN_RAM = 0; + evalPos(0); + closeFileOnDevice(); + } else { + PROGRAM_IN_RAM = 1; + evalPos(PROGRAM_LOAD_ADDR); + } + return 0; +} +#endif + +#ifdef ARDUINO + +//Runs a file. +if (compareIgnoreCase(command, "run")) { + if (arg != 1) + return ERROR_ARGUMENT_COUNT; + + PROGRAM_IN_RAM = 1; + evalPos(PROGRAM_LOAD_ADDR); + return 0; +} +#endif +//Loads a file into RAM. +if (compareIgnoreCase(command, "load")) { + + if (arg != 2) + return ERROR_ARGUMENT_COUNT; + + char fileName[20]; + char fPos = 0; + if (argsType[1] != TYPE_STR) + return ERROR_INVALID_TYPE; + char err = copyStringIntoEvalBuff(argsStart[1], argsSize[1]); + if (err != 0) return err; + char c; + while (c = readCharFromEvalBuff()) { + #ifdef ARDUINO + if (c >= 'a' && c <= 'z') c -= 'a' - 'A'; + #endif + if (fPos == 19) + return ERROR_INVALID_OPTION; + fileName[fPos++] = c; + } + fileName[fPos] = 0; + + if (!fileExistsOnDevice(fileName)) + return ERROR_FILE_NOT_FOUND; + + openFileOnDevice(fileName); + ibword s = sizeOfFileOnDevice(); + PROGRAM_LOAD_ADDR = sizeRAM() - s - 1; + printString("Loading "); + printInt(s + 1); + printString(" bytes.\n"); + for (ibword i = 0; i < s; i++) { + char rc = readFileOnDevice(i); + writeRAM(PROGRAM_LOAD_ADDR + i, rc); + //lcdPutChar(rc); + } + writeRAM(PROGRAM_LOAD_ADDR + s, 0); + printString("Done.\n"); + closeFileOnDevice(); + + return 0; +} + +#ifdef ARDUINO + +//Loads a file into RAM. +if (compareIgnoreCase(command, "edit")) { + + if (arg != 2) + return ERROR_ARGUMENT_COUNT; + + char fileName[9]; + char fPos = 0; + if (argsType[1] != TYPE_STR) + return ERROR_INVALID_TYPE; + char err = copyStringIntoEvalBuff(argsStart[1], argsSize[1]); + if (err != 0) return err; + char c; + while (c = readCharFromEvalBuff()) { + if (c >= 'a' && c <= 'z') c -= 'a' - 'A'; + if (fPos == 8) + return ERROR_INVALID_OPTION; + fileName[fPos++] = c; + } + fileName[fPos] = 0; + + ibword newSize = -1; + if (!fileExistsOnDevice(fileName)) { + newSize = linesEditor(0, 4, 20); + } else { + openFileOnDevice(fileName); + ibword s = sizeOfFileOnDevice(); + unsigned short x = 0, y = 0; + PROGRAM_LOAD_ADDR = sizeRAM() - s - 1; + printString("Loading "); + printInt(s); + printString(" bytes.\n"); + for (ibword i = 0; i < s; i++) { + char rc = readFileOnDevice(i); + if (rc == '\n') { + writeRAM(x + y * LINE_BUFF_MAX, 0); + x = 0; + y++; + } else { + writeRAM(x + y * LINE_BUFF_MAX, rc); + x++; + } + } + writeRAM(y * LINE_BUFF_MAX, 0); + printString("Done.\n"); + closeFileOnDevice(); + newSize = linesEditor(y, 4, 20); + } + + if (newSize != -1) { + File oldFile = openFile(NULL, fileName); + if (oldFile.status == 0) + deleteFile(&oldFile); + if (newSize > 4) { + printString("Saving...\n"); + File newFile = createFile(newSize + 1, NULL, fileName); + seekFile(&newFile, 0); + unsigned short row = 0; + unsigned short col = 0; + for (unsigned short i = 0; i < newSize; i++) { + char c = readRAM(row * LINE_BUFF_MAX + col); + if (c == 0) { + writeFile(&newFile, '\n'); + col = 0; + row++; + } else { + writeFile(&newFile, c); + col++; + } + } + writeFile(&newFile, 0); + printString("Done.\n"); + } + } + + AVL_ROOT = 0; + AVL_END = 0; + return 0; +} + +if (compareIgnoreCase(command, "files")) { + if (arg != 1) + return ERROR_ARGUMENT_COUNT; + + char name[20]; + char fpos = 0; + while (listFilesInFolder(NULL, name)) { + printString(name); + printString("..."); + File f = openFile(NULL, name); + printFloat(f.size); + fpos++; + if (fpos == 4) { + readChar(); + backspace(); + fpos = 0; + } + printString("\n"); + } + return 0; +} + + +//Loads a file into RAM. +if (compareIgnoreCase(command, "delete")) { + + if (arg != 2) + return ERROR_ARGUMENT_COUNT; + + char fileName[20]; + char fPos = 0; + if (argsType[1] != TYPE_STR) + return ERROR_INVALID_TYPE; + char err = copyStringIntoEvalBuff(argsStart[1], argsSize[1]); + if (err != 0) return err; + char c; + while (c = readCharFromEvalBuff()) { + if (c >= 'a' && c <= 'z') c -= 'a' - 'A'; + if (fPos == 19) + return ERROR_INVALID_OPTION; + fileName[fPos++] = c; + } + fileName[fPos] = 0; + + if (!fileExistsOnDevice(fileName)) + return ERROR_FILE_NOT_FOUND; + + File file = openFile(NULL, fileName); + deleteFile(&file); + + return 0; +} + +if (compareIgnoreCase(command, "random")) { + if (arg != 1) + return ERROR_ARGUMENT_COUNT; + + unsigned short seed = KB_RANDOM * 49627 + 49627; + float rnd = (float)seed / (float)65535; + + if (hasArrow) { + if (!isAlpha(outputKey[0])) + return ERROR_INVALID_TYPE; + writeNum(outputAddress, rnd); + } else { + printFloat(rnd); + printString("\n"); + } + + return 0; +} + +//Clear screen. +if (compareIgnoreCase(command, "cls")) { + if (arg != 1) + return ERROR_ARGUMENT_COUNT; + lcdClear(); + return 0; +} + +#endif + + +if (compareIgnoreCase(command, "floor")) { + if (arg != 2) + return ERROR_ARGUMENT_COUNT; + + if (argsType[1] != TYPE_NUM) + return ERROR_INVALID_TYPE; + + char err = copyFormulaIntoEvalBuff(argsStart[1], argsSize[1]); + if (err != 0) return err; + + float num = (unsigned long)evaluateFormula(); + + if (hasArrow) { + if (!isAlpha(outputKey[0])) + return ERROR_INVALID_TYPE; + writeNum(outputAddress, num); + } else { + printFloat(num); + printString("\n"); + } + + return 0; +} + + +//Converts a string into a number. +if (compareIgnoreCase(command, "value")) { + + if (arg != 2) + return ERROR_ARGUMENT_COUNT; + + char str[21]; + char strPos = 0; + if (argsType[1] != TYPE_STR) + return ERROR_INVALID_TYPE; + char err = copyStringIntoEvalBuff(argsStart[1], argsSize[1]); + if (err != 0) return err; + char c; + while (c = readCharFromEvalBuff()) { + if (strPos == 20) break; + str[strPos++] = c; + } + str[strPos] = 0; + float val = atof(str); + + if (hasArrow) { + if (!isAlpha(outputKey[0])) + return ERROR_INVALID_TYPE; + writeNum(outputAddress, val); + } else { + printFloat(val); + printString("\n"); + } + + return 0; +} + +//Clears variables. +if (compareIgnoreCase(command, "clear")) { + if (arg != 1) + return ERROR_ARGUMENT_COUNT; + AVL_ROOT = 0; + AVL_END = 0; + return 0; +} + +#ifndef ARDUINO +//Peeks at the RAM. +if (compareIgnoreCase(command, "peek")) { + + if (arg != 2) + return ERROR_ARGUMENT_COUNT; + + if (argsType[1] != TYPE_NUM) + return ERROR_INVALID_TYPE; + char err = copyFormulaIntoEvalBuff(argsStart[1], argsSize[1]); + if (err != 0) return err; + if (pos < 0 || pos >= sizeRAM()) + return ERROR_OUT_OF_BOUNDS; + ibword pos = (ibword)evaluateFormula(); + + if (hasArrow) { + if (!isAlpha(outputKey[0])) + return ERROR_INVALID_TYPE; + writeNum(outputAddress, readRAM(pos)); + } else { + printFloat(readRAM(pos)); + printString("\n"); + } + return 0; +} + +//Writes to the RAM. +if (compareIgnoreCase(command, "poke")) { + char err; + if (arg != 3) + return ERROR_ARGUMENT_COUNT; + + ibword a; + if (argsType[1] != TYPE_NUM) + return ERROR_INVALID_TYPE; + err = copyFormulaIntoEvalBuff(argsStart[1], argsSize[1]); + if (err != 0) return err; + a = (ibword)evaluateFormula(); + + //float b; + char b; + if (argsType[2] != TYPE_NUM) + return ERROR_INVALID_TYPE; + err = copyFormulaIntoEvalBuff(argsStart[2], argsSize[2]); + if (err != 0) return err; + b = (char)evaluateFormula(); + + if (a < AVL_END || a >= sizeRAM()) + return ERROR_OUT_OF_BOUNDS; + + writeRAM(a, b); + return 0; +} +#endif \ No newline at end of file diff --git a/src/edit.c b/src/edit.c new file mode 100755 index 0000000..5465758 --- /dev/null +++ b/src/edit.c @@ -0,0 +1,204 @@ +void linesEditorCalcSizes(unsigned short line, unsigned short *sizes, char rows) { + for (char i = 0; i < rows; i++) { + unsigned short j = 0; + while (readRAM(j + (line + i) * LINE_BUFF_MAX) != 0) { + j++; + } + sizes[i] = j; + } +} + +unsigned short linesEditorCalcSize(unsigned short lines) { + unsigned short size = 0; + for (unsigned short i = 0; i < lines; i++) { + char c = readRAM(i * LINE_BUFF_MAX); + unsigned short j = 0; + while (c != 0) { + size++; + j++; + c = readRAM(i * LINE_BUFF_MAX + j); + } + size++; + } + return size; +} + +short linesEditor(short lines, char rows, char cols) { + unsigned short line = 0; + char x = 0, y = 0, i, j; + unsigned short sizes[rows]; + unsigned short shifts[rows]; + for (char i = 0; i < rows; i++) { + shifts[i] = 0; + } + while (lines < 4) { + writeRAM(LINE_BUFF_MAX * lines, 0); + lines++; + } + linesEditorCalcSizes(0, sizes, rows); + while (1) { + for (i = 0; i < rows; i++) { + for (j = 0; j < cols; j++) { + unsigned short pos = (j + shifts[i]) + (i + line) * LINE_BUFF_MAX; + char c = readRAM(pos); + + lcdSetCursor(i, j); + if (j >= sizes[i]) + lcdWriteData(' '); + else if (sizes[i] - cols - shifts[i] + 1 > 0 && j == cols - 1) + lcdWriteData(0x7E); + else if (shifts[i] > 0 && j == 0) + lcdWriteData(0x7F); + else + lcdWriteData(c == 0 ? ' ' : c); + } + } + + lcdSetCursor(y, x); + char userInput = readChar(); + switch (userInput) { + //Up. + case 17: + y--; + if (y == (char)-1) { + if (line > 0) + line--; + y++; + } + for (i = 0; i < rows; i++) { + if (i != y) + shifts[i] = 0; + } + break; + //Left. + case 18: + x--; + if (x == (char)-1) { + if (shifts[y] > 0) + shifts[y]--; + x++; + } + break; + //Down. + case 19: + y++; + if (y == rows) { + line++; + if (line > lines - rows) + line--; + y--; + } + for (i = 0; i < rows; i++) { + if (i != y) + shifts[i] = 0; + } + break; + //Right. + case 20: + x++; + if (x == cols) { + shifts[y]++; + x--; + if (shifts[y] + x >= sizes[y] + 1) + shifts[y]--; + } + break; + //Escape. + case 27: + lcdClear(); + return linesEditorCalcSize(lines); + break; + //No save. + case '`': + lcdClear(); + return -1; + break; + //Backspace. + case 8: + if (sizes[y] == 0 || (x == 0 && shifts[y] == 0)) { + line += y; + for (unsigned short ro = line; ro <= lines; ro++) { + unsigned short co = 0; + char c; + do { + c = readRAM((1 + ro) * LINE_BUFF_MAX + co); + writeRAM(ro * LINE_BUFF_MAX + co, c); + co++; + } while (c != 0); + } + lines--; + line -= y; + } else { + for (i = x + shifts[y]; i <= x + shifts[y] + sizes[y]; i++) { + writeRAM((line + y) * LINE_BUFF_MAX + i - 1, + readRAM((line + y) * LINE_BUFF_MAX + i)); + } + x--; + if (x == (char)-1) { + if (shifts[y] > 0) + shifts[y]--; + x++; + } + } + break; + //Delete. + case 127: + writeRAM( (line + y) * LINE_BUFF_MAX , 0); + break; + //Enter. + case 10: + line += y; + for (unsigned short ro = lines - 1; ro > line && ro != (unsigned short)-1; ro--) { + unsigned short co = 0; + char c; + do { + c = readRAM(ro * LINE_BUFF_MAX + co); + writeRAM((1 + ro) * LINE_BUFF_MAX + co, c); + co++; + } while (c != 0); + } + writeRAM( (line + 1) * LINE_BUFF_MAX, 0); + lines++; + line -= y; + y++; + if (y == rows) { + line++; + if (line > lines - rows) + line--; + y--; + } + for (i = 0; i < rows; i++) { + if (i != y) + shifts[i] = 0; + } + break; + default: + if (sizes[y] >= LINE_BUFF_MAX - 1) + break; + for (i = sizes[y] + 1; i > x + shifts[y]; i--) { + writeRAM((line + y) * LINE_BUFF_MAX + i, + readRAM((line + y) * LINE_BUFF_MAX + i - 1)); + } + writeRAM((line + y) * LINE_BUFF_MAX + x + shifts[y], userInput); + x++; + if (x == cols) { + shifts[y]++; + x--; + } + break; + } + while (lines < 4) { + writeRAM(LINE_BUFF_MAX * lines, 0); + lines++; + } + while (line + rows > lines && line != 0) { + line--; + } + linesEditorCalcSizes(line, sizes, rows); + if (x + shifts[y] >= sizes[y] + 1) { + x = sizes[y] - shifts[y]; + } + } + + +} diff --git a/src/hardware/23LC1024.c b/src/hardware/23LC1024.c new file mode 100755 index 0000000..f3dab2d --- /dev/null +++ b/src/hardware/23LC1024.c @@ -0,0 +1,86 @@ + +//Shift out a byte. +void SRAM_CLOCK_BYTE_OUT(char b) { + for (char i = 0; i < 8; i++) { + if (b & 0b10000000) { + digitalWrite(SRAM_PIN_SI, HIGH); + } else { + digitalWrite(SRAM_PIN_SI, LOW); + } + digitalWrite(SRAM_PIN_SCK, HIGH); + digitalWrite(SRAM_PIN_SCK, LOW); + b = b << 1; + } +} + +//Shift in a byte. +char SRAM_CLOCK_BYTE_IN() { + char b = 0; + for (char i = 0; i < 8; i++) { + b = b << 1; + if (i != 0) { + digitalWrite(SRAM_PIN_SCK, HIGH); + digitalWrite(SRAM_PIN_SCK, LOW); + } + if (digitalRead(SRAM_PIN_SO)) + b += 1; + } + return b; +} + +//Set read mode. +char SRAM_READ_MODE() { + digitalWrite(SRAM_PIN_SCK, LOW); + digitalWrite(SRAM_PIN_CS, LOW); + SRAM_CLOCK_BYTE_OUT(0x05); + char c = SRAM_CLOCK_BYTE_IN(); + digitalWrite(SRAM_PIN_CS, HIGH); + return c; +} + +//Set write mode. +void SRAM_WRITE_MODE(char m) { + digitalWrite(SRAM_PIN_SCK, LOW); + digitalWrite(SRAM_PIN_CS, LOW); + SRAM_CLOCK_BYTE_OUT(0x01); + SRAM_CLOCK_BYTE_OUT(m); + digitalWrite(SRAM_PIN_CS, HIGH); +} + + +//Initialize SRAM chip in Byte Write mode. +void sramSetup(char pinCS, char pinSCK, char pinSO, char pinSI) { + SRAM_PIN_CS = pinCS; + SRAM_PIN_SCK = pinSCK; + SRAM_PIN_SO = pinSO; + SRAM_PIN_SI = pinSI; + pinMode(SRAM_PIN_SO, INPUT); + pinMode(SRAM_PIN_SI, OUTPUT); + pinMode(SRAM_PIN_SCK, OUTPUT); + pinMode(SRAM_PIN_CS, OUTPUT); + SRAM_WRITE_MODE(0x00); +} + +//Writes byte b to address a. +void sramWrite(long a, char b) { + digitalWrite(SRAM_PIN_CS, LOW); + SRAM_CLOCK_BYTE_OUT(0x02); + SRAM_CLOCK_BYTE_OUT( (a & 0b10000000000000000) >> 16); + SRAM_CLOCK_BYTE_OUT( (a & 0b01111111100000000) >> 8); + SRAM_CLOCK_BYTE_OUT( (a & 0b00000000011111111) ); + SRAM_CLOCK_BYTE_OUT(b); + digitalWrite(SRAM_PIN_CS, HIGH); +} + +//Reads byte from address a. +char sramRead(long a) { + digitalWrite(SRAM_PIN_CS, LOW); + SRAM_CLOCK_BYTE_OUT(0x03); + SRAM_CLOCK_BYTE_OUT( (a & 0b10000000000000000) >> 16); + SRAM_CLOCK_BYTE_OUT( (a & 0b01111111100000000) >> 8); + SRAM_CLOCK_BYTE_OUT( (a & 0b00000000011111111) ); + char b = SRAM_CLOCK_BYTE_IN(); + digitalWrite(SRAM_PIN_CS, HIGH); + return b; +} + diff --git a/src/hardware/23LC1024.h b/src/hardware/23LC1024.h new file mode 100755 index 0000000..5a92d46 --- /dev/null +++ b/src/hardware/23LC1024.h @@ -0,0 +1,33 @@ +#ifndef LIB_23LC1024 +#define LIB_23LC1024 + +//Pin definitions. +char SRAM_PIN_CS; +char SRAM_PIN_SCK; +char SRAM_PIN_SO; +char SRAM_PIN_SI; + +//Shift out a byte. +void SRAM_CLOCK_BYTE_OUT(char b); + +//Shift in a byte. +char SRAM_CLOCK_BYTE_IN(); + +//Set read mode. +char SRAM_READ_MODE(); + +//Set write mode. +void SRAM_WRITE_MODE(char m); + +//Initialize SRAM chip in Byte Write mode. +void sramSetup(char pinCS, char pinSCK, char pinSO, char pinSI); + +//Writes byte b to address a. +void sramWrite(long a, char b); + +//Reads byte from address a. +char sramRead(long a); + +#include "23LC1024.c" + +#endif diff --git a/src/hardware/LCD2004.h b/src/hardware/LCD2004.h new file mode 100755 index 0000000..cb16bd0 --- /dev/null +++ b/src/hardware/LCD2004.h @@ -0,0 +1,162 @@ +#define LCD_ROWS 4 +#define LCD_COLS 20 +char LCD_ROW; +char LCD_COL; +char PIN_LCD_CLK; +char PIN_LCD_DATA; +char PIN_LCD_RS; +char PIN_LCD_EN; +char LCD_DATA[LCD_COLS * LCD_ROWS]; + +void lcdSetByte(char b) { + for (unsigned char i = 0; i < 8; i++) { + if (b & 0b10000000) + digitalWrite(PIN_LCD_DATA, HIGH); + else + digitalWrite(PIN_LCD_DATA, LOW); + digitalWrite(PIN_LCD_CLK, HIGH); + digitalWrite(PIN_LCD_CLK, LOW); + b <<= 1; + } + digitalWrite(PIN_LCD_EN, HIGH); + digitalWrite(PIN_LCD_EN, LOW); +} + +void lcdWriteRegister(char b) { + digitalWrite(PIN_LCD_RS, LOW); + lcdSetByte(b); +} + +void lcdWriteData(char b) { + digitalWrite(PIN_LCD_RS, HIGH); + lcdSetByte(b); +} + +void lcdInit(char pinEN, char pinRS, char pinData, char pinClock) { + PIN_LCD_EN = pinEN; + PIN_LCD_RS = pinRS; + PIN_LCD_DATA = pinData; + PIN_LCD_CLK = pinClock; + digitalWrite(PIN_LCD_CLK, LOW); + digitalWrite(PIN_LCD_DATA, LOW); + digitalWrite(PIN_LCD_RS, LOW); + digitalWrite(PIN_LCD_EN, LOW); + pinMode(PIN_LCD_CLK, OUTPUT); + pinMode(PIN_LCD_DATA, OUTPUT); + pinMode(PIN_LCD_RS, OUTPUT); + pinMode(PIN_LCD_EN, OUTPUT); + delay(100); + lcdWriteRegister(0x30); + delay(5); + lcdWriteRegister(0x30); + delay(1); + lcdWriteRegister(0x30); + delay(1); + lcdWriteRegister(0x38); + delay(1); + lcdWriteRegister(0x08); + delay(1); + lcdWriteRegister(0x01); + delay(3); + lcdWriteRegister(0x06); + delay(1); + lcdWriteRegister(0x0F); + delay(1); + LCD_ROW = 0; + LCD_COL = 0; + for (int i = 0; i < LCD_ROWS * LCD_COLS; i++) { + LCD_DATA[i] = ' '; + } +} + +void lcdCursor(char toggle) { + if (toggle) lcdWriteRegister(0x0F); + else lcdWriteRegister(0x0C); +} + +void lcdCursorBlink(char blink) { + if (blink) lcdWriteRegister(0x0F); + else lcdWriteRegister(0x0E); +} + +void lcdClear() { + lcdWriteRegister(0x01); + delay(1); + lcdWriteRegister(0x02); + delay(1); + LCD_ROW = 0; + LCD_COL = 0; +} + +void lcdSetCursor(char row, char col) { + switch (row) { + case 0: + lcdWriteRegister(0x80 + col); + break; + case 1: + lcdWriteRegister(0xC0 + col); + break; + case 2: + lcdWriteRegister(0x94 + col); + break; + case 3: + lcdWriteRegister(0xD4 + col); + break; + } +} + +void lcdScroll() { + char tmpRow = LCD_ROW - 1; + lcdClear(); + for (unsigned char y = 0; y < LCD_ROWS - 1; y++) { + lcdSetCursor(y, 0); + for (unsigned char x = 0; x < LCD_COLS; x++) { + LCD_DATA[y * LCD_COLS + x] = LCD_DATA[(y + 1) * LCD_COLS + x]; + LCD_DATA[(y + 1) * LCD_COLS + x] = ' '; + lcdWriteData(LCD_DATA[y * LCD_COLS + x]); + } + } + LCD_ROW = tmpRow; + lcdSetCursor(LCD_ROW, 0); +} + +void lcdNewline() { + LCD_ROW++; + LCD_COL = 0; + if (LCD_ROW == 4) { + lcdScroll(); + } else { + lcdSetCursor(LCD_ROW, 0); + } + +} + +void lcdPutChar(char c) { + int i; + if (c == '\n') { + lcdNewline(); + } else { + lcdWriteData(c); + LCD_DATA[LCD_ROW * LCD_COLS + LCD_COL] = c; + LCD_COL++; + if (LCD_COL == LCD_COLS) { + LCD_COL = 0; + LCD_ROW++; + if (LCD_ROW == 4) { + lcdScroll(); + } else { + lcdSetCursor(LCD_ROW, 0); + } + } + } +} + +void lcdBackspace() { + if (LCD_COL == 0) { + LCD_COL = LCD_COLS - 1; + LCD_ROW--; + } else { + LCD_COL--; + } + lcdSetCursor(LCD_ROW, LCD_COL); +} \ No newline at end of file diff --git a/src/hardware/file/AT24C256.h b/src/hardware/file/AT24C256.h new file mode 100755 index 0000000..bfea388 --- /dev/null +++ b/src/hardware/file/AT24C256.h @@ -0,0 +1,74 @@ +#include "i2c.h" +char EEPROM_ADDRESS; +char EEPROM_STATUS; + +void eepromWrite(unsigned int addr, char val) { + EEPROM_STATUS = 1; + i2cBeginTransmission(); + i2cSend(0b10100000 | EEPROM_ADDRESS); + if (i2cAcknowledge() != 0) { + EEPROM_STATUS = 0; + return; + } + i2cSend(addr >> 8); + if (i2cAcknowledge() != 0) { + EEPROM_STATUS = 0; + return; + } + i2cSend(addr & 0xFF); + if (i2cAcknowledge() != 0) { + EEPROM_STATUS = 0; + return; + } + i2cSend(val); + if (i2cAcknowledge() != 0) { + EEPROM_STATUS = 0; + return; + } + i2cEndTransmission(); + delay(5); +} + +char eepromRead(unsigned int addr) { + EEPROM_STATUS = 1; + char val = 0; + i2cBeginTransmission(); + i2cSend(0b10100000 | EEPROM_ADDRESS); + if (i2cAcknowledge() != 0) { + EEPROM_STATUS = 0; + return 0; + } + i2cSend(addr >> 8); + if (i2cAcknowledge() != 0) { + EEPROM_STATUS = 0; + return 0; + } + i2cSend(addr & 0xFF); + if (i2cAcknowledge() != 0) { + EEPROM_STATUS = 0; + return 0; + } + + i2cBeginTransmission(); + i2cSend(0b10100001 | EEPROM_ADDRESS); + if (i2cAcknowledge() != 0) { + EEPROM_STATUS = 0; + return 0; + } + val = i2cReceive(); + if (i2cAcknowledge() != 1) { + EEPROM_STATUS = 0; + return 0; + } + i2cEndTransmission(); + + return val; +} + +char eepromSetup(char addr, int pinSDA, int pinSCL) { + i2cSetup(pinSDA, pinSCL); + EEPROM_ADDRESS = (addr << 1) & 0b110; + eepromRead(0); + return EEPROM_STATUS; +} + diff --git a/src/hardware/file/file.c b/src/hardware/file/file.c new file mode 100755 index 0000000..f65a3be --- /dev/null +++ b/src/hardware/file/file.c @@ -0,0 +1,661 @@ +//Make sure the data that's written is okay. +//Only write datathat's necessary. +void writeToEEPROMSafe(short addr, char data) { + while (eepromRead(addr) != data) { + eepromWrite(addr, data); + } +} + +//Copy data to the EEPROM from a buffer. +void copyToEEPROM(short addr, void *vdata, short size) { + char *data = (char*)vdata; + for (short i = 0; i < size; i++) { + writeToEEPROMSafe(addr + i, *(data + i)); + } +} + +//Copy data from the EEPROM into a buffer. +void copyFromEEPROM(short addr, void *vdata, short size) { + char *data = (char*)vdata; + for (short i = 0; i < size; i++) { + *(data + i) = eepromRead(addr + i); + } +} + +//Reformats the EEPROM and clears all data. +void eepromReformat() { + //Set the file list size to be 0. + char fileSize = 0; + copyToEEPROM(FILE_SIZE_ADDR, &fileSize, sizeof(char)); + //Set the journal to be empty. + short journalSize = 0; + copyToEEPROM(JOURNAL_SIZE_ADDR, &journalSize, sizeof(short)); + //Set the file data size to be empty. + short dataSize = 0; + copyToEEPROM(DATA_SIZE_ADDR, &dataSize, sizeof(short)); +} + +//Compare file names. +char compareFileNames(char *a, char *b) { + char i; + for (i = 0; i < FILE_NAME_SIZE; i++) { + if (a[i] == 0) { + if (b[i] == 0) + return 1; + else + return 0; + } + if (b[i] == 0) { + if (a[i] == 0) + return 1; + else + return 0; + } + + if (a[i] != b[i]) + return 0; + } + return 1; +} + +//Looks for a file within a given directory. +// Returns the index to its file name block. +char findFileNameBlock(char directory, char *name, char type) { + FileNameBlock file; + char addr = 0; + //Fetch size. + char size; + copyFromEEPROM(FILE_SIZE_ADDR, &size, sizeof(char)); + if (size == 0) return undefined; + //Look for file name. + do { + copyFromEEPROM(FILE_NAME_ADDR + sizeof(FileNameBlock) * addr, + &file, sizeof(FileNameBlock)); + if (file.flag == type) { + if (compareFileNames(name, file.name) && file.directory == directory) { + return addr; + } + } + addr++; + } while (addr != size); + return undefined; +} + +//Checks if a directory exists. +char directoryExists(char directory) { + + //If it's at the root, it exists. + if (directory == (char)undefined) { + return 1; + } + + //Fetch size. + char size; + copyFromEEPROM(FILE_SIZE_ADDR, &size, sizeof(char)); + + //If the directory is too large or too small, it can't exist. + if (directory < 0 || directory >= size) + return 0; + //Load file name block. + FileNameBlock file; + copyFromEEPROM(FILE_NAME_ADDR + sizeof(FileNameBlock) * directory, + &file, sizeof(FileNameBlock)); + //If the entry is not a folder, it doesn't exist. + if (file.flag != FILE_FLAG_FOLDER) + return 0; + //It exists. + return 1; +} + +//Find the first empty file name block. +char findEmptyFileNameBlock() { + FileNameBlock file; + char addr = 0; + //Fetch size. + char size; + copyFromEEPROM(FILE_SIZE_ADDR, &size, sizeof(char)); + //Look for first empty block. + do { + copyFromEEPROM(FILE_NAME_ADDR + sizeof(FileNameBlock) * addr, + &file, sizeof(FileNameBlock)); + if (file.flag == FILE_FLAG_EMPTY) + return addr; + addr++; + } while (addr != size); + //If we reached the end, that is our empty block assuming + // we have not maxed out how many files we can store. + if (size != MAX_FILES) + return size; + else + return undefined; +} + +//Create a new file name block. +// Returns index of created file. +// Returns undefined if there is no space left. +// Does NOT check if the file already exists. +// Nor does it check if its directory exists. +// Size is the total size of the data the file contains. +char createFileNameBlock(char directory, char type, short size, char *name) { + FileNameBlock file; + //Fetch the index of the first empty file name block. + char index = findEmptyFileNameBlock(); + //If it failed to find one, there are no spaces left. + if (index == (char)undefined) { + return undefined; + } + //Load the empty file name block. + copyFromEEPROM(FILE_NAME_ADDR + sizeof(FileNameBlock) * index, + &file, sizeof(FileNameBlock)); + //If it's a FINAL entry, make a new FINAL entry. + if (file.flag == FILE_FLAG_FINAL) { + //Make sure there is room for a new final entry. + if (index + 1 != MAX_FILES) { + //Create our new FINAL entry. + copyToEEPROM(FILE_NAME_ADDR + sizeof(FileNameBlock) * (index + 1), + &file, sizeof(FileNameBlock)); + } + } + //Fill the name with spaces. + for (char i = 0; i < FILE_NAME_SIZE; i++) + file.name[i] = 0; + //Copy file name to file name block. + for (char i = 0; i < FILE_NAME_SIZE; i++) { + if (name[i] == 0) + break; + file.name[i] = name[i]; + } + //Set the flag. + file.flag = type; + //Set the directory. + file.directory = directory; + //Set size. + file.size = size; + copyToEEPROM(FILE_NAME_ADDR + sizeof(FileNameBlock) * index, + &file, sizeof(FileNameBlock)); + //Increment size. + char fileSize; + copyFromEEPROM(FILE_SIZE_ADDR, &fileSize, sizeof(char)); + fileSize++; + copyToEEPROM(FILE_SIZE_ADDR, &fileSize, sizeof(char)); + return index; +} + +//Deletes a file name block at an index. +// Does NOT check if the file exists. +void deleteFileNameBlock(char index) { + char size; + copyFromEEPROM(FILE_SIZE_ADDR, &size, sizeof(char)); + //If the index is too small or too large, just do nothing. + if (index < 0 || index >= size) + return; + //If we are deleting a file name at the end, + // then you can simply decrease the size. + if (index == size - 1) { + size--; + copyToEEPROM(FILE_SIZE_ADDR, &size, sizeof(char)); + return; + } + //Store an empty file flag. + FileNameBlock file; + file.flag = FILE_FLAG_EMPTY; + copyToEEPROM(FILE_NAME_ADDR + sizeof(FileNameBlock) * index, + &file, sizeof(FileNameBlock)); +} + +//Creates a folder. +Folder createFolder(Folder *parent, char *name) { + Folder myFolder; + myFolder.status = 0; + char directory; + if (parent == NULL) + directory = undefined; + else + directory = parent->index; + myFolder.directory = directory; + //Check if the directory exists. + if (!directoryExists(directory)) { + myFolder.status = 1; + } + //Check if the file doesn't already exist. + if (findFileNameBlock(directory, name, FILE_FLAG_FOLDER) != (char)undefined) { + myFolder.status = 2; + return myFolder; + } + //Create new file name block. + char index = createFileNameBlock(directory, FILE_FLAG_FOLDER, 0, name); + myFolder.index = index; + //Copy name to folder. + for (char i = 0; i < FILE_NAME_SIZE; i++) { + if (name[i] == 0) { + myFolder.name[i] = 0; + break; + } else { + myFolder.name[i] = name[i]; + } + } + myFolder.name[FILE_NAME_SIZE] = 0; + myFolder.seek = 0; + return myFolder; + +} + +//Creates a file and returns it. +// If it failed to create the file, it will still +// return a file but the status will not be 0. +// 1 Directory doesn't exist. +// 2 File already exists. +// 3 Max files reached. +File createFile(short size, Folder *folder, char *name) { + File myFile; + myFile.address = undefined; + //Fetch directory index. + char directory; + if (folder == NULL) + directory = undefined; + else + directory = folder->index; + //Check if the directory exists. + if (!directoryExists(directory)) { + myFile.status = 1; + return myFile; + } + //Check if the file doesn't already exist. + if (findFileNameBlock(directory, name, FILE_FLAG_FILE) != (char)undefined) { + myFile.status = 2; + return myFile; + } + //Create new file name block. + char index = createFileNameBlock(directory, FILE_FLAG_FILE, size, name); + myFile.index = index; + //Copy name to file. + for (char i = 0; i < FILE_NAME_SIZE; i++) { + if (name[i] == 0) { + myFile.name[i] = 0; + break; + } else { + myFile.name[i] = name[i]; + } + } + myFile.name[FILE_NAME_SIZE] = 0; + //If it failed, then we can't store anymore files. + if (index == (char)undefined) { + myFile.status = 3; + return myFile; + } + //Get a count of how many data blocks will we need. + short count = size % DATA_BLOCK_SIZE == 0 ? + size / DATA_BLOCK_SIZE : size / DATA_BLOCK_SIZE + 1; + //Offset. + short offset = size % DATA_BLOCK_SIZE; + //Load journal size. + short journalSize; + copyFromEEPROM(JOURNAL_SIZE_ADDR, &journalSize, sizeof(short)); + short oldJournalSize = journalSize; + //Address and previous address.... + short addr = undefined; + short paddr = undefined; + + //While the journal size isn't zero... + while (journalSize > 0 && count > 0) { + //Pop an address off the journal. + FileDataBlock data; + paddr = addr; + journalSize--; + copyFromEEPROM(JOURNAL_ADDR + sizeof(short) * journalSize, + &addr, sizeof(short)); + //If we haven't set the address yet, this is the address. + if (myFile.address == (short)undefined) { + myFile.address = addr; + } else { + //Link previous data block to this one. + copyFromEEPROM(DATA_ADDR + paddr, &data, sizeof(short) * 2); + if (data.next != addr || data.size != DATA_BLOCK_SIZE) { + data.next = addr; + data.size = DATA_BLOCK_SIZE; + copyToEEPROM(DATA_ADDR + paddr, &data, sizeof(short) * 2); + } + } + + //Loop until this journal entry does not have a next data. + do { + //Load the data block. + copyFromEEPROM(DATA_ADDR + addr, &data, sizeof(short) * 2); + //Decrement the count. + count--; + //Go to the next data block. + paddr = addr; + addr = data.next; + } while (addr != (short)undefined && count > 0); + + + //If we still have data left but our count is empty, + // we need to tell the journal there's still empty + // space left. + if (addr != (short)undefined) { + //Push next item onto journal. + copyToEEPROM(JOURNAL_ADDR + sizeof(short) * journalSize, + &addr, sizeof(short)); + journalSize++; + } + + //If we've reached the last item, make the end undefined. + if (count == 0) { + //Make the last file data block empty. + data.next = undefined; + data.size = offset; + if (paddr != (short)undefined) { + copyToEEPROM(DATA_ADDR + paddr, &data, sizeof(short) * 2); + } else { + copyToEEPROM(DATA_ADDR + myFile.address, &data, sizeof(short) * 2); + } + } + + //If we did reach the end, update addr. + if (addr == (short)undefined) { + addr = paddr; + } + } + //Save new journal size. + if (journalSize != oldJournalSize) + copyToEEPROM(JOURNAL_SIZE_ADDR, &journalSize, sizeof(short)); + + //Load data size. + short dataSize; + copyFromEEPROM(DATA_SIZE_ADDR, &dataSize, sizeof(short)); + short oldDataSize = dataSize; + //If we still have count left even after using + // the whole journal... + while (count > 0) { + FileDataBlock data; + paddr = addr; + addr = dataSize; + dataSize += sizeof(FileDataBlock); + //If we haven't set the address yet, this is the address. + if (myFile.address == (short)undefined) { + myFile.address = addr; + } else { + //Link previous data block to this one. + copyFromEEPROM(DATA_ADDR + paddr, &data, sizeof(short) * 2); + if (data.next != addr || data.size != DATA_BLOCK_SIZE) { + data.next = addr; + data.size = DATA_BLOCK_SIZE; + copyToEEPROM(DATA_ADDR + paddr, &data, sizeof(short) * 2); + } + } + count--; + + //If we've reached the last item, make the end undefined. + if (count == 0) { + //Make the last file data block empty. + if (data.next != (short)undefined || data.size != offset) { + data.next = undefined; + data.size = offset; + copyToEEPROM(DATA_ADDR + addr, &data, sizeof(short) * 2); + } + } + } + //Save new size. + if (dataSize != oldDataSize) + copyToEEPROM(DATA_SIZE_ADDR, &dataSize, sizeof(short)); + + myFile.status = 0; + myFile.size = size; + myFile.seekAddr = myFile.address; + myFile.seekPos = 0; + myFile.directory = directory; + + //Insert the address into the file name block. + FileNameBlock fnb; + copyFromEEPROM(FILE_NAME_ADDR + sizeof(FileNameBlock) * index, + &fnb, sizeof(FileNameBlock)); + fnb.address = myFile.address; + copyToEEPROM(FILE_NAME_ADDR + sizeof(FileNameBlock) * index, + &fnb, sizeof(FileNameBlock)); + + return myFile; +} + +//Deletes a file. +void deleteFile(File *myFile) { + //Delete the file name block. + deleteFileNameBlock(myFile->index); + //Append its address to the journal. + if (myFile->size > 0) { + short journalSize; + copyFromEEPROM(JOURNAL_SIZE_ADDR, &journalSize, sizeof(short)); + copyToEEPROM(JOURNAL_ADDR + sizeof(short) * journalSize, + &myFile->address, sizeof(short)); + journalSize++; + copyToEEPROM(JOURNAL_SIZE_ADDR, &journalSize, sizeof(short)); + myFile->size = 0; + } +} + +//Deletes a folder. +void deleteFolder(Folder *myFolder) { + //Delete the folder name block. + deleteFileNameBlock(myFolder->index); +} + +//Resizes a file to a new size. +void resizeFile(File *myFile, short newSize) { + //Deleting the file and recreating it will resize it. + // This is because the journal is a stack, so the + // free space created from the most recently deleted + // file is the first space to be filled in by a new + // file. This means that the file will preserve its + // data if deleted and immediately recreated. + deleteFile(myFile); + Folder myFolder; + myFolder.directory = myFile->directory; + File newFile = createFile(newSize, &myFolder, myFile->name); + char *myFilePtr = (char*)myFile; + char *newFilePtr = (char*)&newFile; + for (char i = 0; i < sizeof(File); i++) { + *myFilePtr = *newFilePtr; + } +} + +void printFileData(File f) { + short count = f.size % DATA_BLOCK_SIZE == 0 ? + f.size / DATA_BLOCK_SIZE : f.size / DATA_BLOCK_SIZE + 1; + if (count == 0) { + return; + } + + short addr = f.address; + int i = 0; + do { + FileDataBlock data; + copyFromEEPROM(DATA_ADDR + addr, &data, sizeof(FileDataBlock)); + addr = data.next; + } while (addr != (short)undefined && i < 30); +} + +//List files in a folder. +// Returns 0 when reaches the end. +// Stores name in "name". +char listFilesInFolder(Folder *folder, char *name) { + char directory; + if (folder == NULL) + directory = undefined; + else + directory = folder->index; + FileNameBlock file; + char addr; + if (folder == NULL) + addr = FILE_ROOT_SEEK; + else + addr = folder->seek; + //Fetch size. + char size; + copyFromEEPROM(FILE_SIZE_ADDR, &size, sizeof(char)); + //If we've reached the end, no more files. + if (folder == NULL) { + if (FILE_ROOT_SEEK >= size) { + FILE_ROOT_SEEK = 0; + return 0; + } + } else { + if (folder->seek >= size) { + folder->seek = 0; + return 0; + } + } + //Look for file name. + do { + copyFromEEPROM(FILE_NAME_ADDR + sizeof(FileNameBlock) * addr, + &file, sizeof(FileNameBlock)); + if (file.flag != FILE_FLAG_EMPTY) { + if (file.directory == directory) { + //Update seek. + if (folder == NULL) + FILE_ROOT_SEEK = addr + 1; + else + folder->seek = addr + 1; + //Load name. + char namePos = 0; + if (file.flag == FILE_FLAG_FOLDER) + name[namePos++] = '/'; + for (char i = 0; i < FILE_NAME_SIZE; i++) { + if (file.name[i] == 0) break; + name[namePos++] = file.name[i]; + } + if (file.flag == FILE_FLAG_FOLDER) + name[namePos++] = '/'; + name[namePos] = 0; + return 1; + } + } + addr++; + } while (addr != size); + if (folder == NULL) + FILE_ROOT_SEEK = 0; + else + folder->seek = 0; + return 0; +} + +//Opens a folder. +Folder openFolder(Folder *parent, char *name) { + char directory; + if (parent == NULL) + directory = undefined; + else + directory = parent->index; + Folder myFolder; + myFolder.status = 0; + myFolder.directory = directory; + myFolder.index = findFileNameBlock(directory, name, FILE_FLAG_FOLDER); + if (myFolder.index == (char)undefined) { + myFolder.status = 1; + return myFolder; + } + for (char i = 0; i < FILE_NAME_SIZE; i++) + myFolder.name[i] = name[i]; + myFolder.name[FILE_NAME_SIZE] = 0; + myFolder.seek = 0; + return myFolder; +} + +//Opens a file. +File openFile(Folder *parent, char *name) { + char directory; + if (parent == NULL) + directory = undefined; + else + directory = parent->index; + File myFile; + myFile.status = 0; + myFile.directory = directory; + myFile.index = findFileNameBlock(directory, name, FILE_FLAG_FILE); + if (myFile.index == (char)undefined) { + myFile.status = 1; + return myFile; + } + FileNameBlock fnb; + copyFromEEPROM(FILE_NAME_ADDR + sizeof(FileNameBlock) * myFile.index, + &fnb, sizeof(FileNameBlock)); + + for (char i = 0; i < FILE_NAME_SIZE; i++) + myFile.name[i] = name[i]; + myFile.name[FILE_NAME_SIZE] = 0; + + myFile.size = fnb.size; + myFile.address = fnb.address; + myFile.seekPos = 0; + myFile.seekAddr = myFile.address; + + return myFile; +} + +//Reads a byte from a file. +char readFile(File *file) { + char ret = 0; + + //Load the file data block. + FileDataBlock data; + copyFromEEPROM(DATA_ADDR + file->seekAddr, &data, sizeof(FileDataBlock)); + + //Return nothing if we're at the end. + if (data.next == (short)undefined) { + if (file->seekPos == data.size) { + return 0; + } + } + + //Load the character. + copyFromEEPROM(DATA_ADDR + file->seekAddr + file->seekPos + sizeof(short) * 2, &ret, 1); + + //Increase the seek pointer. + if (file->seekPos < DATA_BLOCK_SIZE) + file->seekPos++; + + //If we've left the block, look for the next block. + if (file->seekPos == DATA_BLOCK_SIZE) { + if (file->seekAddr != (short)undefined) { + file->seekPos = 0; + file->seekAddr = data.next; + } + } + + return ret; +} + +//Changes the seek pointer of a file. +void seekFile(File *file, short pos) { + file->seekPos = 0; + file->seekAddr = file->address; + for (short i = 0; i < pos; i++) + readFile(file); +} + +//Reads a byte from a file. +void writeFile(File *file, char c) { + //Load the file data block. + FileDataBlock data; + copyFromEEPROM(DATA_ADDR + file->seekAddr, &data, sizeof(short) * 2); + + //Return if we're at the end. + if (data.next == (short)undefined) { + if (file->seekPos == DATA_BLOCK_SIZE) { + return; + } + } + + //Store the character. + copyToEEPROM(DATA_ADDR + file->seekAddr + sizeof(short) * 2 + file->seekPos, &c, 1); + + //Increase the seek pointer. + if (file->seekPos < DATA_BLOCK_SIZE) + file->seekPos++; + + //If we've left the block, look for the next block. + if (file->seekPos == DATA_BLOCK_SIZE) { + if (file->seekAddr != (short)undefined) { + file->seekPos = 0; + file->seekAddr = data.next; + } + } +} diff --git a/src/hardware/file/file.h b/src/hardware/file/file.h new file mode 100755 index 0000000..e93fe6c --- /dev/null +++ b/src/hardware/file/file.h @@ -0,0 +1,130 @@ +/* + A file system for EEPROMs. + + File names are stored linearly, meaning finding a file + takes O(n) time where n is the max number of files the + device can hold. + + File data blocks are connected through a linked list. + This allows for quick retrieval of all the data of a + file once its file name is found. It also allows for + data blocks to not have to be stored linearly on the + device, but can be broken up and different parts of + the file stored in different locations in order to + use as much of the memory device as possible. + + File name blocks consist of... + 1. The files name as a string of ASCII characters. + All file names are the same length. If the file + name does not fill the entire length, spaces + are appended onto the end. + 2. A file flag. This specifies whether the file is + indeed a file, a folder, an empty entry, or the + final entry in the file list. + 3. A directory. This is the index of the folder + that the file belongs to. + 4. A size telling you the number of bytes in the + file. + 5. An address. If the file is indeed a file, this + will be the address of its first data block. + + File data blocks consist of... + 1. A size. This is how much of the data block is + actually filled up by the file data. + 2. A "next" pointer which points to the next data + block. + 3. The data itself. + + The journal is broken up into two parts: + 1. The journal size, which is simply a single + value representing the current size of the + journal. + 2. The journal itself, which is a list of pointers + to empty data blocks. + Note that this is NOT a journaling file system. The + "journal" here simply refers to a stack that keeps + track of the location of deleted file blocks. + + + +*/ + +#ifndef LIB_EEPROM_FILE +#define LIB_EEPROM_FILE + +#define undefined -1 +#define MAX_FILES 64 +#define FILE_NAME_SIZE 8 +#define DATA_BLOCK_SIZE 64 +#define FILE_FLAG_FILE 0 +#define FILE_FLAG_FOLDER 1 +#define FILE_FLAG_EMPTY 2 +#define FILE_FLAG_FINAL 3 + +typedef struct { + char name[FILE_NAME_SIZE]; + char flag; + char directory; + short size; + short address; +} FileNameBlock; + +typedef struct { + short next; + short size; + char data[DATA_BLOCK_SIZE]; +} FileDataBlock; + +typedef struct { + short size; + short address; + short seekPos; + short seekAddr; + char status; + char index; + char directory; + char name[FILE_NAME_SIZE + 1]; +} File; + +typedef struct { + char status; + char index; + char directory; + char name[FILE_NAME_SIZE + 1]; + char seek; +} Folder; + +#define FILE_SIZE_ADDR 0 +#define FILE_NAME_ADDR sizeof(char) +#define JOURNAL_SIZE_ADDR MAX_FILES * sizeof(FileNameBlock) +#define JOURNAL_ADDR JOURNAL_SIZE_ADDR + sizeof(short) +#define DATA_SIZE_ADDR JOURNAL_ADDR + sizeof(short) * MAX_FILES +#define DATA_ADDR DATA_SIZE_ADDR + sizeof(short) +char FILE_ROOT_SEEK = 0; +#include "AT24C256.h" + +void copyToEEPROM(short addr, void *vdata, short size); +void copyFromEEPROM(short addr, void *vdata, short size); +void eepromReformat(); +char compareFileNames(char *a, char *b); +char findFileNameBlock(char directory, char *name, char type); +char directoryExists(char directory); +char findEmptyFileNameBlock(); +char createFileNameBlock(short addr, char directory, char type, short size, char *name); +void deleteFileNameBlock(char index); +Folder createFolder(Folder *parent, char *name); +File createFile(short size, Folder *folder, char *name); +void deleteFile(File *myFile); +void deleteFolder(Folder *myFolder); +void resizeFile(File *myFile, short newSize); +void printFileData(File f); +char listFilesInFolder(Folder *folder, char *name); +Folder openFolder(Folder *parent, char *name); +File openFile(Folder *parent, char *name); +char readFile(File *file); +void seekFile(File *file, short pos); +void writeFile(File *file, char c); + +#include "file.c" + +#endif diff --git a/src/hardware/file/i2c.h b/src/hardware/file/i2c.h new file mode 100755 index 0000000..f9b4282 --- /dev/null +++ b/src/hardware/file/i2c.h @@ -0,0 +1,76 @@ +char I2C_PIN_SCL; +char I2C_PIN_SDA; + +//Read a digital pin (open collector). +char i2cDigitalRead(char pin) { + pinMode(pin, INPUT_PULLUP); + return digitalRead(pin); +} + +//Write a digital pin (open collector). +void i2cDigitalWrite(char pin, char val) { + if (val == LOW) { + digitalWrite(pin, LOW); + pinMode(pin, OUTPUT); + } else { + pinMode(pin, INPUT_PULLUP); + } +} + +//Setup I2C. +void i2cSetup(char pinSDA, char pinSCL) { + I2C_PIN_SCL = pinSCL; + I2C_PIN_SDA = pinSDA; + i2cDigitalWrite(I2C_PIN_SCL, LOW); + i2cDigitalWrite(I2C_PIN_SDA, LOW); +} + +//Begin a transmission. +void i2cBeginTransmission() { + i2cDigitalWrite(I2C_PIN_SCL, HIGH); + i2cDigitalWrite(I2C_PIN_SDA, HIGH); + i2cDigitalWrite(I2C_PIN_SDA, LOW); + i2cDigitalWrite(I2C_PIN_SCL, LOW); +} + +//End a transmission. +void i2cEndTransmission() { + i2cDigitalWrite(I2C_PIN_SCL, LOW); + i2cDigitalWrite(I2C_PIN_SDA, LOW); + i2cDigitalWrite(I2C_PIN_SCL, HIGH); + i2cDigitalWrite(I2C_PIN_SDA, HIGH); +} + +//Send a byte. +void i2cSend(char b) { + for (char i = 0; i < 8; i++) { + if (b & 0b10000000) + i2cDigitalWrite(I2C_PIN_SDA, HIGH); + else + i2cDigitalWrite(I2C_PIN_SDA, LOW); + i2cDigitalWrite(I2C_PIN_SCL, HIGH); + i2cDigitalWrite(I2C_PIN_SCL, LOW); + b <<= 1; + } +} + +//Read a byte. +char i2cReceive() { + char b = 0; + for (char i = 0; i < 8; i++) { + b <<= 1; + if (i2cDigitalRead(I2C_PIN_SDA)) + b++; + i2cDigitalWrite(I2C_PIN_SCL, HIGH); + i2cDigitalWrite(I2C_PIN_SCL, LOW); + } + return b; +} + +//Check for acknowledge. +char i2cAcknowledge() { + char r = i2cDigitalRead(I2C_PIN_SDA); + i2cDigitalWrite(I2C_PIN_SCL, HIGH); + i2cDigitalWrite(I2C_PIN_SCL, LOW); + return r; +} diff --git a/src/hardware/hardware.c b/src/hardware/hardware.c new file mode 100755 index 0000000..37db3fa --- /dev/null +++ b/src/hardware/hardware.c @@ -0,0 +1,139 @@ +//This file handles hardware specifics. + +#ifdef DESKTOP + +#include +#define false 0 +#define true 1 +unsigned char RAM[125000]; +FILE *OPEN_FILE; + +//Get size of RAM. +ibword sizeRAM() { + return 125000; +} + +//Read a byte from RAM. +char readRAM(ibword pos) { + return RAM[pos]; +} + +//Write a byte to RAM. +void writeRAM(ibword pos, char b) { + RAM[pos] = b; +} + +//Write a character to the screen. +void writeChar(char c) { + printf("%c", c); +} + +//Read a character from the keyboard. +char readChar() { + char c; + scanf("%c", &c); + return c; +} + + +void backspace() {}; + +//Check if a file exists. +bool fileExistsOnDevice(char *fname) { + FILE *file = fopen(fname, "r"); + if (file == NULL) { + return false; + } else { + fclose(file); + return true; + } +} + +//Open a file. +void openFileOnDevice(char *fname) { + OPEN_FILE = fopen(fname, "r"); +} + +//Closes a file. +void closeFileOnDevice() { + fclose(OPEN_FILE); +} + +//Read character from file at address. +char readFileOnDevice(ibword pos) { + fseek(OPEN_FILE, pos, SEEK_SET); + return (char)fgetc(OPEN_FILE); +} + +ibword sizeOfFileOnDevice() { + fseek(OPEN_FILE, 0L, SEEK_END); + return ftell(OPEN_FILE); +} + + +#endif + +#ifdef ATMEGA328P + +void writeChar(char c) { + lcdPutChar(c); +} + +char readChar() { + char c = kbGetChar(); + if (c != (char)-1 && c != 0 && c != 0x08) lcdPutChar(c); + return c; +} + +void backspace() { + lcdBackspace(); + lcdPutChar(' '); + lcdBackspace(); +} + +ibword sizeRAM() { + return 64000; +} + +//File RAM_FILE; +//Read a byte from RAM. +char readRAM(ibword pos) { + return sramRead(pos); +} + +//Write a byte to RAM. +void writeRAM(ibword pos, char b) { + sramWrite(pos, b); +} + +File OPEN_FILE; + +//Check if a file exists. +bool fileExistsOnDevice(char *fname) { + OPEN_FILE = openFile(NULL, fname); + if (OPEN_FILE.status == 0) return 1; + return 0; +} + +//Open a file. +void openFileOnDevice(char *fname) { + OPEN_FILE = openFile(NULL, fname); +} + +//Closes a file. +void closeFileOnDevice() {} + +//Read character from file at address. +ibword FILE_PPOS = -1; +char readFileOnDevice(ibword pos) { + if (FILE_PPOS != pos - 1 && pos != 0) + seekFile(&OPEN_FILE, pos); + FILE_PPOS = pos; + return readFile(&OPEN_FILE); +} + +ibword sizeOfFileOnDevice() { + return OPEN_FILE.size; +} + +#endif diff --git a/src/hardware/hardware.h b/src/hardware/hardware.h new file mode 100755 index 0000000..39ba0d5 --- /dev/null +++ b/src/hardware/hardware.h @@ -0,0 +1,32 @@ +//This file handles hardware specifics. +#ifndef HARDWARE_H +#define HARDWARE_H +#ifdef DESKTOP +typedef unsigned char bool; +#endif +#define undefined -1 +#ifdef DESKTOP +typedef unsigned int ibword; +#endif +#ifdef ARDUINO +typedef unsigned short ibword; +#endif +char readRAM(ibword pos); +void writeRAM(ibword pos, char b); +void writeChar(char c); +void waitForInput(); +char readChar(); +bool fileExistsOnDevice(char *fname); +void openFileOnDevice(char *fname); +void closeFileOnDevice(); +char readFileOnDevice(ibword pos); +#ifdef ATMEGA328P +#include +#include "23LC1024.h" +#include "LCD2004.h" +#include "keyboard.c" +#include "file/file.h" +#endif +#include "hardware.c" + +#endif diff --git a/src/hardware/i2c.c b/src/hardware/i2c.c new file mode 100755 index 0000000..f550796 --- /dev/null +++ b/src/hardware/i2c.c @@ -0,0 +1,73 @@ +//Read a digital pin (open collector). +char i2cDigitalRead(char pin) { + pinMode(pin, INPUT_PULLUP); + return digitalRead(pin); +} + +//Write a digital pin (open collector). +void i2cDigitalWrite(char pin, char val) { + if (val == LOW) { + digitalWrite(pin, LOW); + pinMode(pin, OUTPUT); + } else { + pinMode(pin, INPUT_PULLUP); + } +} + +//Setup I2C. +void i2cSetup(char pinSDA, char pinSCL) { + I2C_PIN_SCL = pinSCL; + I2C_PIN_SDA = pinSDA; + i2cDigitalWrite(I2C_PIN_SCL, LOW); + i2cDigitalWrite(I2C_PIN_SDA, LOW); +} + +//Begin a transmission. +void i2cBeginTransmission() { + i2cDigitalWrite(I2C_PIN_SCL, HIGH); + i2cDigitalWrite(I2C_PIN_SDA, HIGH); + i2cDigitalWrite(I2C_PIN_SDA, LOW); + i2cDigitalWrite(I2C_PIN_SCL, LOW); +} + +//End a transmission. +void i2cEndTransmission() { + i2cDigitalWrite(I2C_PIN_SCL, LOW); + i2cDigitalWrite(I2C_PIN_SDA, LOW); + i2cDigitalWrite(I2C_PIN_SCL, HIGH); + i2cDigitalWrite(I2C_PIN_SDA, HIGH); +} + +//Send a byte. +void i2cSend(char b) { + for (char i = 0; i < 8; i++) { + if (b & 0b10000000) + i2cDigitalWrite(I2C_PIN_SDA, HIGH); + else + i2cDigitalWrite(I2C_PIN_SDA, LOW); + i2cDigitalWrite(I2C_PIN_SCL, HIGH); + i2cDigitalWrite(I2C_PIN_SCL, LOW); + b <<= 1; + } +} + +//Read a byte. +char i2cReceive() { + char b = 0; + for (char i = 0; i < 8; i++) { + b <<= 1; + if (i2cDigitalRead(I2C_PIN_SDA)) + b++; + i2cDigitalWrite(I2C_PIN_SCL, HIGH); + i2cDigitalWrite(I2C_PIN_SCL, LOW); + } + return b; +} + +//Check for acknowledge. +char i2cAcknowledge() { + char r = i2cDigitalRead(I2C_PIN_SDA); + i2cDigitalWrite(I2C_PIN_SCL, HIGH); + i2cDigitalWrite(I2C_PIN_SCL, LOW); + return r; +} diff --git a/src/hardware/i2c.h b/src/hardware/i2c.h new file mode 100755 index 0000000..fd336c7 --- /dev/null +++ b/src/hardware/i2c.h @@ -0,0 +1,34 @@ +#ifndef LIB_I2C +#define LIB_I2C + +//Pins. +char I2C_PIN_SCL; +char I2C_PIN_SDA; + +//Read a digital pin (open collector). +char i2cDigitalRead(char pin); + +//Write a digital pin (open collector). +void i2cDigitalWrite(char pin, char val); + +//Setup I2C. +void i2cSetup(char pinSDA, char pinSCL); + +//Begin a transmission. +void i2cBeginTransmission(); + +//End a transmission. +void i2cEndTransmission(); + +//Send a byte. +void i2cSend(char b); + +//Read a byte. +char i2cReceive(); + +//Check for acknowledge. +char i2cAcknowledge(); + +#include "i2c.c" + +#endif diff --git a/src/hardware/keyboard.c b/src/hardware/keyboard.c new file mode 100755 index 0000000..5ea9e62 --- /dev/null +++ b/src/hardware/keyboard.c @@ -0,0 +1,91 @@ +char KB_PIN_DATA; +char KB_PIN_CLK; +char KB_BUFFER[20]; +unsigned short KB_RANDOM; + +//Write a digital pin (open collector). +void kbDigitalWrite(char pin, char val) { + if (val == LOW) { + digitalWrite(pin, LOW); + pinMode(pin, OUTPUT); + } else { + pinMode(pin, INPUT_PULLUP); + } +} + +//Setup keyboard. +void kbSetup(char pinDATA, char pinCLK) { + KB_PIN_DATA = pinDATA; + KB_PIN_CLK = pinCLK; + kbDigitalWrite(KB_PIN_CLK, LOW); + kbDigitalWrite(KB_PIN_DATA, LOW); + delay(10); + kbDigitalWrite(KB_PIN_CLK, LOW); + kbDigitalWrite(KB_PIN_DATA, HIGH); +} + +//Read a digital pin (open collector). +char kbDigitalRead(char pin) { + pinMode(pin, INPUT_PULLUP); + return digitalRead(pin); +} + +char kbRead() { + + char pos = 0; + + for (char i = 0; i < 11; i++) { + while (!kbDigitalRead(KB_PIN_CLK)) + KB_RANDOM++; + while (kbDigitalRead(KB_PIN_CLK)) + KB_RANDOM++; + KB_BUFFER[pos++] = kbDigitalRead(KB_PIN_DATA); + } + + char data = 0; + for (char i = 8; i >= 1; i--) { + data <<= 1; + data |= KB_BUFFER[i]; + } + + return data; +} + +char KB_SHIFT = 0; +char kbGetChar() { + kbDigitalWrite(KB_PIN_CLK, HIGH); + char c; + char extended = 0; + while (1) { + KB_RANDOM++; + c = kbRead(); + if (EEPROM.read(c) == 14 || EEPROM.read(c) == 15) { + KB_SHIFT = 1; + continue; + } + if (c == (char)0xF0) { + c = kbRead(); + if (EEPROM.read(c) == 14 || EEPROM.read(c) == 15) { + KB_SHIFT = 0; + continue; + } + break; + } + if (c == (char)0xE0) { + c = kbRead(); + if (c == (char)0xF0) { + c = kbRead(); + extended = 1; + break; + } + } + } + + kbDigitalWrite(KB_PIN_CLK, LOW); + if (extended) + return EEPROM.read(c + 256); + else if (KB_SHIFT) + return EEPROM.read(c + 128); + else + return EEPROM.read(c); +} \ No newline at end of file diff --git a/src/idyllic.c b/src/idyllic.c new file mode 100755 index 0000000..0c39476 --- /dev/null +++ b/src/idyllic.c @@ -0,0 +1,1162 @@ +#include "parsing/evaluator.h" +char evalPos(ibword pos); +ibword PROGRAM_LOAD_ADDR; +char PROGRAM_IN_RAM; + +#ifdef ARDUINO + #include "edit.c" +#endif + +//Returns -1 if line is too long. +// Otherwise returns offset. +char copyStringIntoLineBuff(char *s) { + ibword i = 0; + while (!isEOL(s[i])) { + LINE_BUFF[i] = s[i]; + i++; + if (i == LINE_BUFF_MAX) + break; + } + if (i == LINE_BUFF_MAX) + return false; + LINE_BUFF[i] = 0; + return true; +} + +ibword copyFileIntoLineBuff(ibword pos) { + ibword i = 0; + char c = PROGRAM_IN_RAM ? readRAM(pos) : readFileOnDevice(pos); + while (!isEOL(c)) { + LINE_BUFF[i++] = c; + pos += 1; + if (i == LINE_BUFF_MAX) + break; + c = PROGRAM_IN_RAM ? readRAM(pos) : readFileOnDevice(pos); + } + if (i == LINE_BUFF_MAX) + return -1; + LINE_BUFF[i] = 0; + return i + 1; +} + +//Evaluate a reference statement. +// 0 No Error. +char evalReference(ibword addr) { + ibword pos = 0; + char c; + char key[KEY_SIZE + 1]; + char p = 0; + + //Skip over garbage whitespace. + c = LINE_BUFF[pos]; + while (isWS(c)) { + c = LINE_BUFF[++pos]; + } + + //Load the key. + while (!isWS(c) && !isEOL(c)) { + key[p++] = c; + c = LINE_BUFF[++pos]; + if (p > KEY_SIZE) + return ERROR_INVALID_KEY; + } + key[p] = 0; + + //Check if there is more garbage text afterwards. + while (isWS(c) && !isEOL(c)) { + c = LINE_BUFF[++pos]; + } + if (!isEOL(c)) + return ERROR_SYNTAX; + if (!verifyKey(key)) + return ERROR_INVALID_KEY; + + //Check if the key exists. + ibword addr2 = findNode(key); + if (addr2 != (ibword)undefined) { + //Return an error if we're trying to + // change the key's address. + if (readAdr(addr2) != addr) + return ERROR_KEY_EXISTS; + return 0; + } + //No issues. Create the key. + dimAdr(key, addr); + + return 0; +} + + +char evalSubroutine(ibword addr) { + char c = 0; + ibword pos = 0; + + //Skip over garbage whitespace. + c = LINE_BUFF[pos]; + while (isWS(c)) { + c = LINE_BUFF[++pos]; + } + + //Remove "sub". + c = LINE_BUFF[pos]; + if (c != 'S' && c != 's') + return ERROR_SYNTAX; + LINE_BUFF[pos] = ' '; + c = LINE_BUFF[++pos]; + if (c != 'U' && c != 'u') + return ERROR_SYNTAX; + LINE_BUFF[pos] = ' '; + c = LINE_BUFF[++pos]; + if (c != 'B' && c != 'b') + return ERROR_SYNTAX; + LINE_BUFF[pos] = ' '; + if (isWS(c)) + return ERROR_SYNTAX; + + char err = evalReference(addr); + if (err != 0) return err; + else return ERROR_SUBROUTINE; +} + +//Evaluate an assignment. +// 0 No error. +// If we are assigning a string that has yet +// to have a size, we can pass the string +// name into "newstr" and it will set the +// size before defining it. +char evalAssignment(char *newstr) { + + char c; + char key[KEY_SIZE]; + char keyPos = 0; + ibword pos = 0; + + //Skip over white space. + c = LINE_BUFF[pos]; + while (isWS(c) && !isEOL(c)) { + c = LINE_BUFF[++pos]; + } + + //Syntax error. + if (isEOL(c)) return 1; + + //Read in key. + if (c == '$') { + key[keyPos++] = c; + c = LINE_BUFF[++pos]; + } + while (isAlphaNum(c) && !isEOL(c)) { + key[keyPos++] = c; + if (keyPos > KEY_SIZE) + return ERROR_INVALID_KEY; + c = LINE_BUFF[++pos]; + } + key[keyPos] = 0; + + //Syntax error. + if (isEOL(c)) return ERROR_SYNTAX; + + //Key doesn't exist. + if (!verifyKey(key)) return ERROR_INVALID_KEY; + + //Check if key exists. + ibword addr; + if (newstr == NULL) + addr = findNode(key); + if (addr == (ibword)undefined && newstr == NULL) + return ERROR_KEY_NOT_FOUND; + + //Skip to equal sign. + char isArray = 0; + while (c != '=' && !isEOL(c)) { + if (c == '[') { + isArray = 1; + break; + } + c = LINE_BUFF[++pos]; + } + + //Fetch array index. + ibword index; + if (isArray) { + char numBuff[11]; + char numBuffPos = 0; + char numIsVar = 0; + char isOnlyNum = 1; + c = LINE_BUFF[++pos]; + while (c != ']') { + if (isEOL(c)) + return ERROR_SYNTAX; + if (isAlpha(c)) + numIsVar = 1; + if (!isNum(c) && !isWS(c)) + isOnlyNum = 0; + if (!isWS(c)) + numBuff[numBuffPos++] = c; + c = LINE_BUFF[++pos]; + } + if (numBuffPos == 0) + return ERROR_SYNTAX; + numBuff[numBuffPos] = 0; + if (numIsVar) { + if (!verifyKey(numBuff)) + return ERROR_SYNTAX; + ibword addrIndex = findNode(numBuff); + if (addrIndex == (ibword)undefined) + return ERROR_KEY_NOT_FOUND; + index = (int)readNum(addrIndex); + } else { + if (isOnlyNum) + index = atoi(numBuff); + else + return ERROR_SYNTAX; + } + index--; + //Skip to equal sign. + while (c != '=' && !isEOL(c)) { + c = LINE_BUFF[++pos]; + } + } + + //Syntax error. + if (isEOL(c)) + return ERROR_SYNTAX; + + //Find start and size. + c = LINE_BUFF[++pos]; + ibword start = pos; + ibword size = 0; + while (!isEOL(c)) { + c = LINE_BUFF[++pos]; + size++; + } + + //Copy formula to eval buff. + if (isAlpha(key[0])) { + if (!verifyFormula(start, size)) + return ERROR_SYNTAX; + char err = copyFormulaIntoEvalBuff(start, size); + if (err != 0) return err; + if (isArray) { + if (index < 0 || index >= readArrSize(addr)) + return ERROR_OUT_OF_BOUNDS; + writeArr(addr, index, evaluateFormula()); + } else + writeNum(addr, evaluateFormula()); + } else if (key[0] == '$') { + //Make sure the string to evaluate is syntactically correct. + if (!verifyString(start, size)) + return ERROR_SYNTAX; + //Load the string for evaluation. + char err = copyStringIntoEvalBuff(start, size); + if (err != 0) return err; + //Fetch the size of the string variable to store. + ibword strSize; + if (newstr == NULL) + strSize = readStrSize(addr); + else + strSize = STRING_SIZE_MAX; + //Iterator. + ibword strPos = 0; + char c = readCharFromEvalBuff(); + if (isArray) { + if (index < 0 || index >= readStrSize(addr)) + return ERROR_OUT_OF_BOUNDS; + writeStr(addr, index, c); + //Reset the buffer. + EVAL_ADR = undefined; + EVAL_STR_POS = 0; + readCharFromEvalBuff(); + } else { + writeRAM(strPos + AVL_END + sizeof(AVL_Node), c); + strPos++; + while (c = readCharFromEvalBuff()) { + writeRAM(strPos + AVL_END + sizeof(AVL_Node), c); + strPos++; + } + if (strPos > strSize && newstr == NULL) { + //Find next node. + AVL_Node n = fetchNode(addr); + while (n.next != (ibword)undefined) { + n = fetchNode(n.next); + } + //Insert new dandling node. + n.next = insertDanglingNode(strPos - strSize); + storeNode(&n); + //Recalculate string. + strPos = 0; + c = readCharFromEvalBuff(); + writeRAM(strPos + AVL_END + sizeof(AVL_Node), c); + strPos++; + while (c = readCharFromEvalBuff()) { + writeRAM(strPos + AVL_END + sizeof(AVL_Node), c); + strPos++; + } + strSize = strPos; + } + //Dim the string if it's specified to. + if (newstr != NULL) { + if (strPos <= 0) + return ERROR_SYNTAX; + char tmp = readRAM(AVL_END + sizeof(AVL_Node)); + addr = dimStr(newstr, strPos); + writeRAM(addr + sizeof(AVL_Node), tmp); + } else { + for (int i = 0; i < strPos; i++) { + writeStr(addr, i, readRAM(i + AVL_END + sizeof(AVL_Node))); + } + if (strPos != strSize) { + writeStr(addr, strPos, 0); + } + } + } + } else { + //Syntax error. + return ERROR_SYNTAX; + } + + return 0; +} + +//Evaluate a conditional. +// 0 No error. +char evalEnd() { + char c; + ibword pos = 0; + + //Skip over white space. + c = LINE_BUFF[pos]; + while (isWS(c) && !isEOL(c)) { + c = LINE_BUFF[++pos]; + } + + //Syntax error. + if (isEOL(c) || (c != 'E' && c != 'e')) + return ERROR_SYNTAX; + c = LINE_BUFF[++pos]; + if (isEOL(c) || (c != 'N' && c != 'n')) + return ERROR_SYNTAX; + c = LINE_BUFF[++pos]; + if (isEOL(c) || (c != 'D' && c != 'd')) + return ERROR_SYNTAX; + + //Skip over white space. + c = LINE_BUFF[++pos]; + while (isWS(c) && !isEOL(c)) { + c = LINE_BUFF[++pos]; + } + + //Syntax error. + if (!isEOL(c)) + return ERROR_SYNTAX; + + return 0; +} + +//Evaluate a conditional. +// 0 No error. +char evalConditional() { + ibword lhsStart = 0; + ibword lhsSize = 0; + ibword rhsStart = 0; + ibword rhsSize = 0; + char cond1 = ' '; + char cond2 = ' '; + char c; + char pos = 0; + char err; + + //Skip over white space. + c = LINE_BUFF[pos]; + while (isWS(c) && !isEOL(c)) { + c = LINE_BUFF[++pos]; + } + + //Syntax error. + if (isEOL(c)) + return ERROR_SYNTAX; + + //Skip over command. + while (!isWS(c) && !isEOL(c)) { + c = LINE_BUFF[++pos]; + } + + //Syntax error. + if (isEOL(c)) + return ERROR_SYNTAX; + + //Skip over white space. + while (isWS(c) && !isEOL(c)) { + c = LINE_BUFF[++pos]; + } + + //Get LHS. + lhsStart = pos; + while (!isWS(c) && !isEOL(c)) { + c = LINE_BUFF[++pos]; + lhsSize++; + } + + //Syntax error. + if (isEOL(c)) + return ERROR_SYNTAX; + + //Skip over white space. + while (isWS(c) && !isEOL(c)) { + c = LINE_BUFF[++pos]; + } + + //Syntax error. + if (isEOL(c)) + return ERROR_SYNTAX; + + //Get the first conditional. + cond1 = c; + c = LINE_BUFF[++pos]; + + //Syntax error. + if (isEOL(c)) + return ERROR_SYNTAX; + + //Get the second conditional. + if (!isWS(c)) { + cond2 = c; + c = LINE_BUFF[++pos]; + } + + //Syntax error. + if (isEOL(c) || !isWS(c)) + return ERROR_SYNTAX; + + //Skip over white space. + while (isWS(c) && !isEOL(c)) { + c = LINE_BUFF[++pos]; + } + + //Get RHS. + rhsStart = pos; + while (!isWS(c) && !isEOL(c)) { + c = LINE_BUFF[++pos]; + rhsSize++; + } + + //Skip over white space. + while (isWS(c) && !isEOL(c)) { + c = LINE_BUFF[++pos]; + } + + //Check for "THEN" + if (isEOL(c) || (c != 't' && c != 'T')) + return ERROR_MISSING_THEN; + c = LINE_BUFF[++pos]; + if (isEOL(c) || (c != 'h' && c != 'H')) + return ERROR_MISSING_THEN; + c = LINE_BUFF[++pos]; + if (isEOL(c) || (c != 'e' && c != 'E')) + return ERROR_MISSING_THEN; + c = LINE_BUFF[++pos]; + if (isEOL(c) || (c != 'n' && c != 'N')) + return ERROR_MISSING_THEN; + c = LINE_BUFF[++pos]; + + //Skip over whitespace. + while (isWS(c) && !isEOL(c)) { + c = LINE_BUFF[++pos]; + } + + //Syntax error. + if (!isEOL(c)) + return ERROR_SYNTAX; + + //Check conditional. + char lhsType = getExprType(lhsStart, lhsSize); + char rhsType = getExprType(rhsStart, rhsSize); + if (lhsType == TYPE_NUM && rhsType == TYPE_NUM) { + float lhs, rhs; + if (!verifyFormula(lhsStart, lhsSize)) + return ERROR_SYNTAX; + err = copyFormulaIntoEvalBuff(lhsStart, lhsSize); + if (err != 0) return err; + lhs = evaluateFormula(); + if (!verifyFormula(rhsStart, rhsSize)) + return ERROR_SYNTAX; + err = copyFormulaIntoEvalBuff(rhsStart, rhsSize); + if (err != 0) return err; + rhs = evaluateFormula(); + //Check the conditions. + if (cond1 == '>' && cond2 == ' ') { + if (!(lhs > rhs)) + return ERROR_CONDITIONAL_TRIGGERED; + } else if (cond1 == '>' && cond2 == '=') { + if (!(lhs >= rhs)) + return ERROR_CONDITIONAL_TRIGGERED; + } else if (cond1 == '<' && cond2 == ' ') { + if (!(lhs < rhs)) + return ERROR_CONDITIONAL_TRIGGERED; + } else if (cond1 == '<' && cond2 == '=') { + if (!(lhs <= rhs)) + return ERROR_CONDITIONAL_TRIGGERED; + } else if (cond1 == '=' && cond2 == '=') { + if (!(lhs == rhs)) + return ERROR_CONDITIONAL_TRIGGERED; + } else if (cond1 == '!' && cond2 == '=') { + if (!(lhs != rhs)) + return ERROR_CONDITIONAL_TRIGGERED; + } else { + return ERROR_SYNTAX; + } + } else if (lhsType == TYPE_STR || rhsType == TYPE_STR) { + char compSize = 8; + char compA[compSize + 1]; + char compB[compSize + 1]; + char compPosA = 0; + char compPosB = 0; + char c; + + //Load string A. + if (!verifyString(lhsStart, lhsSize)) + return ERROR_SYNTAX; + err = copyStringIntoEvalBuff(lhsStart, lhsSize); + if (err != 0) return err; + while (c = readCharFromEvalBuff()) { + compA[compPosA++] = c; + if (compPosA == compSize) + break; + } + compA[compPosA] = 0; + + //Load string B. + if (!verifyString(rhsStart, rhsSize)) + return ERROR_SYNTAX; + err = copyStringIntoEvalBuff(rhsStart, rhsSize); + if (err != 0) return err; + while (c = readCharFromEvalBuff()) { + compB[compPosB++] = c; + if (compPosB == compSize) + break; + } + compB[compPosB] = 0; + + //Check the conditions. + if (cond1 == '=' && cond2 == '=') { + if (strcmp(compA, compB) != 0) + return ERROR_CONDITIONAL_TRIGGERED; + } else if (cond1 == '!' && cond2 == '=') { + if (strcmp(compA, compB) == 0) + return ERROR_CONDITIONAL_TRIGGERED; + } else { + return ERROR_SYNTAX; + } + } + + return ERROR_CONDITIONAL_UNTRIGGERED; + +} +//Evaluate a declaration. +// 0 No error. +char evalDeclaration() { + char c; + char key[KEY_SIZE]; + char keyPos = 0; + ibword pos = 0; + char ret = 0; + bool containsAssignment = false; + + //Skip over white space. + c = LINE_BUFF[pos]; + while (isWS(c) && !isEOL(c)) { + c = LINE_BUFF[++pos]; + } + //Syntax error. + if (isEOL(c)) + return ERROR_SYNTAX; + + //Skip over "dim". + pos += 3; + + //Syntax error. + c = LINE_BUFF[pos]; + if (!isWS(c) || isEOL(c)) + return ERROR_SYNTAX; + + //Skip over white space. + while (isWS(c) && !isEOL(c)) { + c = LINE_BUFF[++pos]; + } + + //Syntax error. + if (isEOL(c)) + return ERROR_SYNTAX; + + //Read in key. + key[keyPos++] = c; + c = LINE_BUFF[++pos]; + while (!isWS(c) && !isEOL(c) && c != '[' && c != '=') { + key[keyPos++] = c; + if (keyPos > KEY_SIZE) + return ERROR_INVALID_KEY; + c = LINE_BUFF[++pos]; + } + key[keyPos] = 0; + + //Check to see if variable name is valid. + if (!verifyKey(key)) + return ERROR_INVALID_KEY; + + //Make sure the variable isn't an address. + if (key[0] == '@') + return ERROR_INVALID_TYPE; + + //Check to see if variable already exists. + if (findNode(key) != (ibword)undefined) + return ERROR_KEY_EXISTS; + + //Syntax error. + char numBuff[11]; + char numPos = 0; + char hasArray = 0; + char smartString = 0; + ibword size = 0; + ibword arrayStart = pos; + ibword arrayEnd = pos; + + //Handle array. + if (c == '[') { + hasArray = 1; + + //Read in size. + char numIsVar = 0; + char isOnlyNum = 1; + c = LINE_BUFF[++pos]; + while (c != ']' && !isEOL(c)) { + if (isEOL(c)) + return ERROR_SYNTAX; + if (isAlpha(c)) + numIsVar = 1; + if (!isNum(c) && !isWS(c)) + isOnlyNum = 0; + if (!isWS(c)) + numBuff[numPos++] = c; + c = LINE_BUFF[++pos]; + } + if (numPos == 0) + return ERROR_SYNTAX; + numBuff[numPos] = 0; + if (numIsVar) { + if (!verifyKey(numBuff)) + return ERROR_SYNTAX; + ibword addrIndex = findNode(numBuff); + if (addrIndex == (ibword)undefined) + return ERROR_KEY_NOT_FOUND; + size = (int)readNum(addrIndex); + } else { + if (isOnlyNum) + size = atoi(numBuff); + else + return ERROR_SYNTAX; + } + arrayEnd = pos; + + //Syntax error. + if (c != ']') + return ERROR_SYNTAX; + c = LINE_BUFF[++pos]; + + //Skip over white space. + while (isWS(c) && !isEOL(c)) { + c = LINE_BUFF[++pos]; + } + + //Syntax error. + if (!isEOL(c) && c != '=') + return ERROR_SYNTAX; + else if (c == '=') + containsAssignment = true; + + //Make sure the string isn't too massive. + if (size > STRING_SIZE_MAX || size < 0) + return ERROR_STRING_TOO_LARGE; + if (key[0] != '$' && size == 0) + return ERROR_STRING_TOO_LARGE; + + //Create the variable. + if (key[0] == '$') + dimStr(key, size); + else + dimArr(key, size); + + } else { + + //Skip over white space. + while (isWS(c) && !isEOL(c)) { + c = LINE_BUFF[++pos]; + } + + //Syntax error. + if (!isEOL(c) && c != '=') + ERROR_SYNTAX; + else if (c == '=') + containsAssignment = true; + + //Create the variable. + if (key[0] == '$') { + smartString = 1; + if (!containsAssignment) + dimStr(key, 0); + } else + dimNum(key, 0); + } + + if (containsAssignment) { + //Remove brackets. + for (ibword i = arrayStart; i < arrayEnd; i++) + LINE_BUFF[i] = ' '; + + //Skip over white space; + pos = 0; + c = LINE_BUFF[pos++]; + while (isWS(c) && !isEOL(c)) { + c = LINE_BUFF[pos++]; + } + //Remove "DIM". + LINE_BUFF[pos - 1] = ' '; + LINE_BUFF[pos] = ' '; + LINE_BUFF[pos + 1] = ' '; + + //Evaluate assignment. + if (smartString) + ret = evalAssignment(key); + else + ret = evalAssignment(NULL); + } + + return ret; +} + +bool compareIgnoreCase(const char *a, const char *b) { + char ca = a[0]; + char cb = b[0]; + char p = 0; + while (ca != 0 && cb != 0) { + char d = ('a' - 'A'); + if ( + ca + d != cb && + ca - d != cb && + ca != cb + ) { + return false; + } + p++; + ca = a[p]; + cb = b[p]; + } + if (ca == 0 && cb == 0) + return true; + return false; +} + +//Evaluates a command. +//Making arrays global saves program space. +#ifdef ARDUINO +char outputKey[KEY_SIZE + 1]; +ibword argsStart[10]; +ibword argsSize[10]; +char argsType[10]; +char command[10]; +#endif +char evalCommand() { + #ifdef DESKTOP + char outputKey[KEY_SIZE + 1]; + ibword argsStart[10]; + ibword argsSize[10]; + char argsType[10]; + char command[10]; + #endif + ibword outputAddress = undefined; + char arg = 1; + char c; + + char commandPos = 0; + ibword pos = 0; + bool isInQuotes = false; + + //Get start of command. + c = LINE_BUFF[pos]; + while (isWS(c) && !isEOL(c)) { + c = LINE_BUFF[++pos]; + } + argsStart[0] = pos; + //Get end of command. + while (!isWS(c) && !isEOL(c)) { + if (!isAlpha(c) && c != '$') + return ERROR_SYNTAX; + if (commandPos == 10) + return ERROR_UNKNOWN_COMMAND; + command[commandPos++] = c; + if (commandPos == 10) + return ERROR_ARGUMENT_COUNT; + c = LINE_BUFF[++pos]; + } + command[commandPos] = 0; + argsSize[0] = pos - argsStart[0]; + + //Get arguments. + while (!isEOL(c)) { + //Get start of argument. + while ( (isWS(c) || c == ',') && !isEOL(c)) { + c = LINE_BUFF[++pos]; + } + argsStart[arg] = pos; + + //Keep track if it only contains white space. + char onlyWhiteSpace = 1; + + //Get end of argument. + while ( (c != ',' || isInQuotes) && !isEOL(c) ) { + if (c == '\"') { + isInQuotes = !isInQuotes; + } + if (!isWS(c)) + onlyWhiteSpace = 0; + c = LINE_BUFF[++pos]; + } + argsSize[arg] = pos - argsStart[arg]; + + //Update argument only if not only white space. + if (!onlyWhiteSpace) + arg++; + } + + //Check for arrow. + bool hasArrow = false; + if (arg >= 2) { + if (LINE_BUFF[argsStart[arg - 1]] == '=' && + LINE_BUFF[argsStart[arg - 1] + 1] == '>') { + arg--; + } + + c = LINE_BUFF[--pos]; + while (pos != argsSize[0]) { + if (c == '\"') break; + if (c == '>') { + c = LINE_BUFF[--pos]; + if (c == '=') { + hasArrow = true; + break; + } + } + c = LINE_BUFF[--pos]; + } + } + + //Remove arrow from arguments. + if (hasArrow) { + //Remove arrow from arguments. + argsSize[arg - 1] = pos - argsStart[arg - 1] - 1; + + //Skip over whitespace. + pos += 2; + c = LINE_BUFF[pos++]; + while (isWS(c) && !isEOL(c)) { + c = LINE_BUFF[pos++]; + } + + //Syntax error. + if (isEOL(c)) + return ERROR_SYNTAX; + + //Read in key. + char keyPos = 0; + while (!isWS(c) && !isEOL(c)) { + outputKey[keyPos++] = c; + c = LINE_BUFF[pos++]; + } + outputKey[keyPos] = 0; + + //Skip over whitespace. + while (isWS(c) && !isEOL(c)) { + c = LINE_BUFF[pos++]; + } + + //Syntax error. + if (!isEOL(c)) + return ERROR_SYNTAX; + + //Check if the key is valid. + if (!verifyKey(outputKey)) + return ERROR_INVALID_KEY; + + //Check if variable exists. + outputAddress = findNode(outputKey); + if (outputAddress == (ibword)undefined) + return ERROR_KEY_NOT_FOUND; + + } + + //Verify types. + for (char i = 1; i < arg; i++) { + argsType[i] = getExprType(argsStart[i], argsSize[i]); + if (argsType[i] == TYPE_NUM) { + if (!verifyFormula(argsStart[i], argsSize[i])) + return ERROR_SYNTAX; + } else { + if (!verifyString(argsStart[i], argsSize[i])) + return ERROR_SYNTAX; + } + } + + #include "commands.c" + + return ERROR_UNKNOWN_COMMAND; + +} + +//Identifies the type of line. +char identifyLineType() { + ibword pos = 0; + bool checkedM = false; + bool isDeclaration = true; + bool isConditional = true; + bool isEnd = true; + bool isSub = true; + char c = LINE_BUFF[pos]; + while (isWS(c) && !isEOL(c)) { + c = LINE_BUFF[++pos]; + } + if (isEOL(c)) return TYPE_EMPTY; + if (c == '@') return TYPE_REFERENCE; + if (c == ';') return TYPE_COMMENT; + if ( (!isAlpha(c)) && c != '$' ) + return TYPE_COMMAND; + if (c != 'D' && c != 'd') + isDeclaration = false; + if (c != 'I' && c != 'i') + isConditional = false; + if (c != 'E' && c != 'e') + isEnd = false; + if (c != 'S' && c != 's') + isSub = false; + c = LINE_BUFF[++pos]; + if (c != 'I' && c != 'i') + isDeclaration = false; + if (c != 'F' && c != 'f') + isConditional = false; + if (c != 'N' && c != 'n') + isEnd = false; + if (c != 'U' && c != 'u') + isSub = false; + char nc = LINE_BUFF[pos + 1]; + if (isConditional && (isWS(nc) || isEOL(nc))) + return TYPE_CONDITIONAL; + while (isAlphaNum(c) && !isEOL(c)) { + c = LINE_BUFF[++pos]; + + if (!checkedM) { + nc = LINE_BUFF[pos + 1]; + if ((c != 'M' && c != 'm') || !isWS(nc)) + isDeclaration = false; + if ((c != 'D' && c != 'd')) + isEnd = false; + if ((c != 'B' && c != 'b')) + isSub = false; + } + checkedM = true; + } + if (isDeclaration && c != '=') + return TYPE_DECLARATION; + if (isEnd && c != '=') + return TYPE_END; + if (isSub && c != '=') + return TYPE_SUBROUTINE; + if (isEOL(c)) return TYPE_COMMAND; + while (isWS(c) && !isEOL(c)) { + c = LINE_BUFF[++pos]; + } + if (isEOL(c)) return TYPE_COMMAND; + if (c == '=' || c == '[') { + c = LINE_BUFF[++pos]; + if (c != '>') return TYPE_ASSIGNMENT; + } + return TYPE_COMMAND; +} + +//Evaluates a single line at a position. +// The addr should be the address of the next line. +char evalLine(ibword pos, ibword addr) { + + char type = identifyLineType(); + char ret = 0; + if (type == TYPE_DECLARATION) { + ret = evalDeclaration(); + } else if (type == TYPE_ASSIGNMENT) { + ret = evalAssignment(NULL); + } else if (type == TYPE_REFERENCE) { + ret = evalReference(addr); + } else if (type == TYPE_COMMAND) { + ret = evalCommand(); + } else if (type == TYPE_CONDITIONAL) { + ret = evalConditional(); + } else if (type == TYPE_END) { + ret = evalEnd(); + } else if (type == TYPE_SUBROUTINE) { + ret = evalSubroutine(addr); + } + return ret; +} + +//Pribwords an error message associated +// with an error code. +void printError(char e) { + switch (e) { + case 1: + printString("Syntax error"); + break; + case 2: + printString("Not found"); + break; + case 3: + printString("Invalid name"); + break; + case 4: + printString("Variable exists"); + break; + case ERROR_OUT_OF_BOUNDS: + printString("Out of bounds"); + break; + case 6: + printString("Invalid type"); + break; + case 7: + printString("Invalid arguments"); + break; + case 10: + printString("Invalid comparison"); + break; + case ERROR_MISSING_THEN: + printString("Missing THEN"); + break; + case ERROR_STRING_TOO_LARGE: + printString("Invalid size"); + break; + case ERROR_UNKNOWN_COMMAND: + printString("Unknown command"); + break; + case ERROR_FILE_NOT_FOUND: + printString("File not found"); + break; + case ERROR_STACK: + printString("Stack error"); + break; + default: + printString("Invalid mode"); + break; + } + +} + +//Evaluates a program at position. +#define subStackSize 10 +#ifdef ARDUINO +ibword subStack[subStackSize]; +char subStackPos = 0; +char skipEnd[subStackSize]; +char skipEndPos = 0; +#endif +char evalPos(ibword pos) { + ibword size; + char eof = 10; + char skipMode = 0; + ibword lineNum = 0; + #ifdef DESKTOP + ibword subStack[subStackSize]; + char subStackPos = 0; + char skipEnd[subStackSize]; + char skipEndPos = 0; + #endif + skipEnd[0] = 0; + while (eof == 10) { + lineNum++; + size = copyFileIntoLineBuff(pos); + if (size == (ibword)-1) return ERROR_SYNTAX; + eof = PROGRAM_IN_RAM ? readRAM(pos+size-1) : readFileOnDevice(pos+size-1); + char err; + char type = identifyLineType(); + if (skipMode > 0) { + if (type == TYPE_END) { + skipMode--; + } else if (type == TYPE_CONDITIONAL || type == TYPE_SUBROUTINE) { + skipMode++; + } + err = 0; + } else if (skipMode != (char)-1) { + err = evalLine(pos, pos + size); + if (type == TYPE_END) { + if (skipEnd[skipEndPos] > 0) { + skipEnd[skipEndPos]--; + } else { + if (subStackPos == 0) + err = ERROR_STACK; + else { + subStackPos--; + skipEndPos--; + pos = subStack[subStackPos]; + eof = 10; + continue; + } + } + } else if (type == TYPE_CONDITIONAL && err == ERROR_CONDITIONAL_UNTRIGGERED) { + skipEnd[skipEndPos]++; + } + } + //Not an actual error. + if (err == ERROR_CONDITIONAL_UNTRIGGERED) + err = 0; + if (err == ERROR_HALTING) + break; + if (err != 0) { + //This error means something occurred + // that requires changing the address. + if (err == ERROR_CHANGE_ADDRESS) { + pos = (ibword)evaluateFormula(); + eof = 10; + skipEnd[skipEndPos] = 0; + continue; + } else if (err == ERROR_CHANGE_ADDRESS_CALL) { + if (subStackPos == subStackSize) { + err = ERROR_STACK; + skipMode = -1; + } + subStack[subStackPos++] = pos + size; + pos = (ibword)evaluateFormula(); + skipEnd[++skipEndPos] = 0; + eof = 10; + continue; + } else if (err == ERROR_CONDITIONAL_TRIGGERED || err == ERROR_SUBROUTINE) { + skipMode = 1; + } else if (err == ERROR_SUBROUTINE) { + skipMode = 1; + } else { + printError(err); + printString(" at line "); + printInt(lineNum); + printString(".\n"); + return err; + } + } + pos += size; + } + + if (skipMode != 0 || skipEnd[skipEndPos] != 0) { + printString("Missing END.\n"); + return 50; + } + + return 0; +} + +//Evaluates a single line. +char eval(char *line) { + if (!copyStringIntoLineBuff(line)) + return ERROR_SYNTAX; + return evalLine(0, 0); +} \ No newline at end of file diff --git a/src/main.c b/src/main.c new file mode 100755 index 0000000..0a8091a --- /dev/null +++ b/src/main.c @@ -0,0 +1,41 @@ +#include "idyllic.c" + +void main(int argc, char **args) { + if (argc == 2) { + if (!fileExistsOnDevice(args[1])) { + printf("File `%s` not found.\n", args[1]); + return; + } else { + openFileOnDevice(args[1]); + PROGRAM_IN_RAM = 0; + evalPos(0); + closeFileOnDevice(); + return; + } + } + char userInput[LINE_BUFF_MAX + 1]; + printString("IdyllicBASIC v0.7\n"); + while (1) { + printString("] "); + char pos = 0; + char c = readChar(); + while (c != '\n') { + userInput[pos++] = c; + if (pos == LINE_BUFF_MAX) + break; + c = readChar(); + } + if (pos != LINE_BUFF_MAX) { + userInput[pos] = 0; + char e; + if ( (e = eval(userInput)) != 0 ) { + if (e == ERROR_HALTING) + break; + printError(e); + printString(".\n"); + } + } else { + printString("Too long.\n"); + } + } +} diff --git a/src/parsing/evaluator.c b/src/parsing/evaluator.c new file mode 100755 index 0000000..9ad179d --- /dev/null +++ b/src/parsing/evaluator.c @@ -0,0 +1,491 @@ +//Gets the type of expression (either a number or a string) +char getExprType(ibword pos, ibword size) { + for (char i = 0; i < size; i++) { + char c = LINE_BUFF[i + pos]; + if (c == '$' || c == '\"') { + return TYPE_STR; + } + } + return TYPE_NUM; +} + + +//Appends a floating poibword number to the end of EVAL_BUFF. +void appendNum(float num) { + char buff[20]; + if ( (ibword)num == num ) + ibwordToString(buff, (ibword)num); + else + floatToString(buff, num); + + for (char i = 0; i < strlen(buff); i++) { + EVAL_BUFF[EVAL_LEN++] = buff[i]; + } +} + +//Appends an address to the end of EVAL_BUFF. +void appendAdr(ibword num) { + char buff[20]; + ibwordToString(buff, num); + for (char i = 0; i < strlen(buff); i++) { + EVAL_BUFF[EVAL_LEN++] = buff[i]; + } +} + +/*5+-3 +-3 +-(5+4)*/ + +// + + +//Copies a numeric formula to EVAL_BUFF for numeric processing. +char copyFormulaIntoEvalBuff(ibword pos, ibword size) { + + short fixerStack[20]; + char fixerStackPos = 0; + char key[KEY_SIZE + 1]; + char varPos = 0; + char c = 0; + char pc = 0; + bool varMode = false; + EVAL_LEN = 0; + EVAL_BUFF[EVAL_LEN++] = '('; + for (char i = 0; i < size; i++) { + if (isWS(LINE_BUFF[pos + i])) continue; + pc = c; + c = LINE_BUFF[pos + i]; + if ((isAlpha(c) || c == '@') && !varMode) { + varMode = true; + varPos = 0; + key[varPos++] = c; + } else if (isAlphaNum(c) && varMode) { + key[varPos++] = c; + } else if (!isAlphaNum(varMode) && varMode) { + key[varPos] = 0; + ibword addr = findNode(key); + if (addr == (ibword)undefined) return ERROR_KEY_NOT_FOUND; + if (key[0] == '@') appendAdr(readAdr(addr)); + else if (LINE_BUFF[pos + i] == '[') { + ibword index; + i += 1; + char numBuffPos = 0; + char numIsVar = 0; + char isOnlyNum = 1; + char numBuff[20]; + char cc = ' '; + for (; cc != ']'; i++) { + if (i == size) return 0; + if (isAlpha(cc)) + numIsVar = 1; + if (!isNum(cc) && !isWS(cc)) + isOnlyNum = 0; + if (!isWS(cc)) + numBuff[numBuffPos++] = cc; + cc = LINE_BUFF[pos + i]; + } + if (numBuffPos == 0) + return ERROR_SYNTAX; + numBuff[numBuffPos] = 0; + if (numIsVar) { + if (!verifyKey(numBuff)) + return ERROR_INVALID_KEY; + ibword addrIndex = findNode(numBuff); + if (addrIndex == (ibword)undefined) + return ERROR_KEY_NOT_FOUND; + index = (int)readNum(addrIndex); + } else { + if (isOnlyNum) + index = atoi(numBuff); + else + return ERROR_SYNTAX; + } + index--; + if (index < 0 || index >= readArrSize(addr)) + return ERROR_OUT_OF_BOUNDS; + + appendNum(readArr(addr, index)); + + } else { + appendNum(readNum(addr)); + } + + + varMode = false; + } + + //Removes excessive parenthesis. + if (c == '(') { + fixerStack[fixerStackPos++] = EVAL_LEN; + } else if (c == ')') { + ibword fs = fixerStack[fixerStackPos - 1]; + fixerStackPos--; + if (fs != (ibword)-1) { + EVAL_BUFF[EVAL_LEN++] = '+'; + EVAL_BUFF[EVAL_LEN++] = '0'; + } + } else if (isOperator(c)) { + fixerStack[fixerStackPos - 1] = -1; + } + + if (!varMode) { + if (c == '-') { + if (pc == 0 || isOperator(pc) || pc == '(') { + EVAL_BUFF[EVAL_LEN++] = '('; + EVAL_BUFF[EVAL_LEN++] = '0'; + EVAL_BUFF[EVAL_LEN++] = '-'; + EVAL_BUFF[EVAL_LEN++] = '1'; + EVAL_BUFF[EVAL_LEN++] = ')'; + EVAL_BUFF[EVAL_LEN++] = '*'; + } else { + EVAL_BUFF[EVAL_LEN++] = c; + } + } else { + EVAL_BUFF[EVAL_LEN++] = c; + } + + } + + } + if (varMode) { + key[varPos] = 0; + ibword addr = findNode(key); + if (addr == (ibword)undefined) return ERROR_KEY_NOT_FOUND; + if (key[0] == '@') appendAdr(readAdr(addr)); + else appendNum(readNum(addr)); + } + + //Need +0 in case no ibwordernal operator. + EVAL_BUFF[EVAL_LEN++] = '+'; + EVAL_BUFF[EVAL_LEN++] = '0'; + EVAL_BUFF[EVAL_LEN++] = ')'; + + + //Remove underscores added. + size = EVAL_LEN; + EVAL_LEN = 0; + for (ibword i = 0; i < size; i++) { + c = EVAL_BUFF[i]; + if (c != '_') { + EVAL_BUFF[EVAL_LEN++] = c; + } + } + EVAL_BUFF[EVAL_LEN] = 0; + + return 0; +} + +//Copies a string or string formula to EVAL_BUFF for string processing. +// Returns false if a variable didn't exist. +char copyStringIntoEvalBuff(ibword pos, ibword size) { + char key[KEY_SIZE + 1]; + char varPos = 0; + bool varMode = false; + bool stringMode = false; + EVAL_LEN = 0; + EVAL_POS = 0; + EVAL_ADR = undefined; + for (char i = 0; i < size; i++) { + char c = LINE_BUFF[pos + i]; + if (!isWS(c) || stringMode) { + if (c == '\"') stringMode = !stringMode; + if (!stringMode) { + if ((isAlpha(c) || c == '@' || c == '$') && !varMode) { + varMode = true; + varPos = 0; + key[varPos++] = c; + } else if (isAlphaNum(c) && varMode) { + key[varPos++] = c; + } else if (!isAlphaNum(varMode) && varMode) { + key[varPos] = 0; + ibword addr = findNode(key); + if (addr == (ibword)undefined) return ERROR_KEY_NOT_FOUND; + if (key[0] == '$' && c != '[') { + EVAL_BUFF[EVAL_LEN++] = '#'; + appendAdr(addr); + EVAL_BUFF[EVAL_LEN++] = ':'; + appendAdr(readStrSize(addr)); + } else if (key[0] == '@') { + appendAdr(readAdr(addr)); + } else if (LINE_BUFF[pos + i] == '[') { + ibword index; + i += 1; + char numBuffPos = 0; + char numIsVar = 0; + char isOnlyNum = 1; + char numBuff[20]; + char cc = ' '; + for (; cc != ']'; i++) { + if (i == size) return 0; + if (isAlpha(cc)) + numIsVar = 1; + if (!isNum(cc) && !isWS(cc)) + isOnlyNum = 0; + if (!isWS(cc)) + numBuff[numBuffPos++] = cc; + cc = LINE_BUFF[pos + i]; + } + if (numBuffPos == 0) + return ERROR_SYNTAX; + numBuff[numBuffPos] = 0; + if (numIsVar) { + if (!verifyKey(numBuff)) + return ERROR_INVALID_KEY; + ibword addrIndex = findNode(numBuff); + if (addrIndex == (ibword)undefined) + return ERROR_KEY_NOT_FOUND; + index = (int)readNum(addrIndex); + } else { + if (isOnlyNum) + index = atoi(numBuff); + else + return ERROR_SYNTAX; + } + index--; + if (key[0] == '$') { + if (index < 0 || index >= readStrSize(addr)) + return ERROR_OUT_OF_BOUNDS; + EVAL_BUFF[EVAL_LEN++] = readStr(addr, index); + } else { + if (index < 0 || index >= readArrSize(addr)) + return ERROR_OUT_OF_BOUNDS; + appendNum(readArr(addr, index)); + } + varMode = false; + continue; + } else { + appendNum(readNum(addr)); + } + + varMode = false; + } + } + + if (!varMode) { + EVAL_BUFF[EVAL_LEN++] = c; + } + } + } + if (varMode) { + key[varPos] = 0; + ibword addr = findNode(key); + if (addr == (ibword)undefined) return ERROR_KEY_NOT_FOUND; + if (key[0] == '$') { + EVAL_BUFF[EVAL_LEN++] = '#'; + appendAdr(addr); + EVAL_BUFF[EVAL_LEN++] = ':'; + appendAdr(readStrSize(addr)); + } else if (key[0] == '@') { + appendAdr(readAdr(addr)); + } else { + appendNum(readNum(addr)); + } + } + EVAL_BUFF[EVAL_LEN] = 0; + return 0; +} + +//Verifies no syntax errors in formulas. +bool verifyFormula(ibword pos, ibword size) { + char balance = 0; + char c = 0; + char pc; + char type = 'x'; + char ptype = ' '; + char ps = ' '; + for (ibword i = 0; i < size; i++) { + pc = c; + c = LINE_BUFF[pos + i]; + if (isWS(c)) { + ps = type; + continue; + } + if (c == '(') { + balance++; + ptype = type; + type = '('; + } else if (c == ')') { + balance--; + ptype = type; + type = ')'; + } else if (!isAlphaNum(c) && !isOperator(c) && !isWS(c) && c != '@') { + if (c == '[') { + if (!isAlphaNum(pc)) return false; + char isVar = 1; + char isNum = 1; + i++; + for (; c != ']'; i++) { + if (i == size) + return false; + c = LINE_BUFF[pos + i]; + if (!isAlphaNum(c) && !isWS(c) && c != ']') + return false; + } + continue; + } + return false; + } + if (isOperator(c)) { + ptype = type; + if (c == '-') type = '-'; + else type = '+'; + } else if (isAlphaNum(c) || c == '@') { + ptype = type; + if (c == '.') type = '.'; + else type = '0'; + } + + if (type == '+') { + if (ptype == '(' || ptype == 'x' || ptype == '+') { + return false; + } + } else if (type == '(') { + if (ptype == ')' || ptype == '0' || ptype == '.') { + return false; + } + } else if (type == ')') { + if (ptype == '(' || ptype == '+') { + return false; + } + } else if (type == '0') { + if (ptype == ')') { + return false; + } + if (ptype == '.' && !isNum(c)) { + return false; + } + if (ps == '0' || ps == '.') { + return false; + } + } else if (type == '.') { + if (ptype == '.' || ptype == ')') { + return false; + } + } + ps = ' '; + } + + if (type == '+' || type == '(' || type == '-') { + return false; + } + + if (balance != 0) + return false; + return true; +} + +//Verifies no syntax errors in string formulas. +bool verifyString(ibword pos, ibword size) { + bool stringMode = false; + char c = 'x'; + char pc; + + for (ibword i = 0; i < size; i++) { + if (isWS(LINE_BUFF[pos + i])) continue; + pc = c; + c = LINE_BUFF[pos + i]; + if (!stringMode) { + if (c == '\"') { + stringMode = true; + } else if (c == '+' && pc == '+') { + return false; + } else if (!isAlphaNum(c) && c != '$' && c != '@' && c != '+') { + if (c == '[') { + if (!isAlphaNum(pc)) return false; + char isVar = 1; + char isNum = 1; + i++; + for (; c != ']'; i++) { + if (i == size) + return false; + c = LINE_BUFF[pos + i]; + if (!isAlphaNum(c) && !isWS(c) && c != ']') + return false; + } + continue; + } + return false; + } + } else if (stringMode) { + if (c == '\"') { + stringMode = false; + } + } + } + if (stringMode) + return false; + return true; +} + +//If EVAL_BUFF contains a string formula, use this to read +// a character from it. Characters are shifted out of it. +// The last character will be a 0. +char readCharFromEvalBuff() { + char c; + + if (EVAL_ADR == (ibword)undefined) { + if (EVAL_POS >= EVAL_LEN) { + EVAL_POS = 0; + EVAL_ADR = undefined; + EVAL_STR_SIZE = 0; + EVAL_STR = false; + EVAL_STR_POS = 0; + return 0; + } + c = EVAL_BUFF[EVAL_POS++]; + + while (c == '\"' || (c == '+' && !EVAL_STR)) { + if (EVAL_POS >= EVAL_LEN) { + EVAL_POS = 0; + EVAL_ADR = undefined; + EVAL_STR_SIZE = 0; + EVAL_STR = false; + return 0; + } + if (c == '\"') EVAL_STR = !EVAL_STR; + c = EVAL_BUFF[EVAL_POS++]; + + + } + //If we encountered a string variable... + if (c == '#' && !EVAL_STR) { + char numBuff[20]; + //Read address. + char numBuffPos = 0; + c = EVAL_BUFF[EVAL_POS++]; + while (isNum(c)) { + numBuff[numBuffPos++] = c; + c = EVAL_BUFF[EVAL_POS++]; + } + numBuff[numBuffPos] = 0; + EVAL_ADR = atoi(numBuff); + //Read size. + numBuffPos = 0; + c = EVAL_BUFF[EVAL_POS++]; + while (isNum(c)) { + numBuff[numBuffPos++] = c; + c = EVAL_BUFF[EVAL_POS++]; + if (EVAL_POS == EVAL_LEN + 1) + break; + } + numBuff[numBuffPos] = 0; + EVAL_STR_SIZE = atoi(numBuff); + return readCharFromEvalBuff(); + } + } else { + if (EVAL_STR_SIZE > 0) { + c = readStr(EVAL_ADR, EVAL_STR_POS++); + if (c == 0) { + EVAL_ADR = undefined; + return readCharFromEvalBuff(); + } + EVAL_STR_SIZE--; + } else { + EVAL_ADR = undefined; + EVAL_STR_POS = 0; + return readCharFromEvalBuff(); + } + } + return c; + +} diff --git a/src/parsing/evaluator.h b/src/parsing/evaluator.h new file mode 100755 index 0000000..0d9d49d --- /dev/null +++ b/src/parsing/evaluator.h @@ -0,0 +1,71 @@ +#include "../variables/variables.c" +#include "formula.c" + +//Error types. +#define ERROR_SYNTAX 1 +#define ERROR_KEY_NOT_FOUND 2 +#define ERROR_INVALID_KEY 3 +#define ERROR_KEY_EXISTS 4 +#define ERROR_OUT_OF_BOUNDS 5 +#define ERROR_INVALID_TYPE 6 +#define ERROR_ARGUMENT_COUNT 7 +#define ERROR_CHANGE_ADDRESS 8 +#define ERROR_CONDITIONAL_TRIGGERED 9 +#define ERROR_UNCONDITIONAL_TRIGGERED 10 +#define ERROR_INVALID_COMPARISON 11 +#define ERROR_MISSING_THEN 12 +#define ERROR_STRING_TOO_LARGE 13 +#define ERROR_INVALID_OPTION 14 +#define ERROR_UNKNOWN_COMMAND 15 +#define ERROR_FILE_NOT_FOUND 16 +#define ERROR_CONDITIONAL_UNTRIGGERED 17 +#define ERROR_HALTING 18 +#define ERROR_SUBROUTINE 19 +#define ERROR_CHANGE_ADDRESS_CALL 20 +#define ERROR_STACK 21 + +//Variable types. +#define TYPE_NUM 0 +#define TYPE_STR 1 +//Line types. +#define TYPE_COMMAND 0 +#define TYPE_DECLARATION 1 +#define TYPE_ASSIGNMENT 2 +#define TYPE_REFERENCE 3 +#define TYPE_CONDITIONAL 4 +#define TYPE_END 5 +#define TYPE_COMMENT 6 +#define TYPE_EMPTY 7 +#define TYPE_SUBROUTINE 8 +#define LINE_BUFF_MAX 100 +#define STRING_SIZE_MAX 1000 +ibword EVAL_POS = 0; +ibword EVAL_ADR = undefined; +ibword EVAL_STR_SIZE = 0; +ibword EVAL_STR_POS = 0; +bool EVAL_STR = false; +char LINE_BUFF[LINE_BUFF_MAX + 1]; + +//Gets the type of expression (either a number or a string) +char getExprType(ibword pos, ibword size); + +//Appends a floating poibword number to the end of EVAL_BUFF. +void appendNum(float num); + +//Appends an address to the end of EVAL_BUFF. +void appendAdr(ibword num); + +//Copies a numeric formula to EVAL_BUFF for numeric processing. +// Returns false if a variable didn't exist. +char copyFormulaIntoEvalBuff(); + +//Copies a string or string formula to EVAL_BUFF for string processing. +// Returns false if a variable didn't exist. +char copyStringIntoEvalBuff(); + +//If EVAL_BUFF contains a string formula, use this to read +// a character from it. Characters are shifted out of it. +// The last character will be a 0. +char readCharFromEvalBuff(); + +#include "evaluator.c" diff --git a/src/parsing/formula.c b/src/parsing/formula.c new file mode 100755 index 0000000..e877034 --- /dev/null +++ b/src/parsing/formula.c @@ -0,0 +1,205 @@ +#include +#include +#include +#include "../hardware/hardware.h" +#include "journal.c" + +#define EVAL_NUM_BUFF_SIZE 13 +#define EVAL_BUFF_SIZE 50 +char EVAL_BUFF[EVAL_BUFF_SIZE]; +char EVAL_NUM_BUFF[EVAL_NUM_BUFF_SIZE]; +char EVAL_LEN; + +void evaluateFormulaOnce() { + char pos = -1; + short max_precedence = -1; + short relative_precedence = 0; + short absolute_precedence = 0; + float LHS = 0; + float RHS = 0; + float output = 0; + char RHS_pos = -1; + char LHS_pos = -1; + char decimal = 0; + char elen = 0; + char oper; + + for (char i = 0; i < EVAL_LEN; i++) { + char c = EVAL_BUFF[i]; + if (c == '=' || c == '~') + absolute_precedence = 1; + else if (c == '+' || c == '-') + absolute_precedence = 2; + else if (c == '*' || c == '/') + absolute_precedence = 3; + else if (isOperator(c)) + absolute_precedence = 4; + else if (c == '(') + relative_precedence += 10; + else if (c == ')') + relative_precedence -= 10; + + if (isOperator(c)) { + short precedence = relative_precedence + absolute_precedence; + if (precedence > max_precedence) { + max_precedence = precedence; + pos = i; + } + } + } + oper = EVAL_BUFF[pos]; + + //Get RHS. + if (EVAL_BUFF[pos + 1] != '[') { + decimal = 0; + for (char i = pos + 1; i < EVAL_LEN; i++) { + RHS_pos = i; + char c = EVAL_BUFF[i]; + if (isOperator(c) || c == '(' || c == ')') { + break; + } else if (c >= '0' && c <= '9') { + RHS *= 10; + RHS += c - '0'; + if (decimal > 0) { + decimal++; + } + } else if (c == '.') { + decimal = 1; + } + } + for (char i = 0; i < decimal - 1; i++) { + RHS /= 10; + } + } else { + for (char i = pos + 1; i < EVAL_LEN; i++) { + RHS_pos = i; + char c = EVAL_BUFF[i]; + if (isOperator(c) || c == '(' || c == ')') { + break; + } else if (c >= '0' && c <= '9') { + RHS *= 10; + RHS += c - '0'; + } + } + RHS = journal_pop(RHS); + } + RHS_pos--; + + //Get LHS. + decimal = 0; + char enb_pos = EVAL_NUM_BUFF_SIZE - 2; + if (EVAL_BUFF[pos - 1] != ']') { + for (char i = pos - 1; i != 255; i--) { + LHS_pos = i; + char c = EVAL_BUFF[i]; + if (isOperator(c) || c == '(' || c == ')') { + break; + } else if ( (c >= '0' && c <= '9') || c == '.' ) { + EVAL_NUM_BUFF[enb_pos--] = c; + } + } + while (enb_pos > 0) { + EVAL_NUM_BUFF[enb_pos] = ' '; + enb_pos--; + } + EVAL_NUM_BUFF[enb_pos] = ' '; + EVAL_NUM_BUFF[EVAL_NUM_BUFF_SIZE - 1] = 0; + LHS = atof(EVAL_NUM_BUFF); + } else { + for (char i = pos - 1; i != 255; i--) { + LHS_pos = i; + char c = EVAL_BUFF[i]; + if (isOperator(c) || c == '(' || c == ')') { + break; + } else if ( (c >= '0' && c <= '9') || c == '.' ) { + EVAL_NUM_BUFF[enb_pos--] = c; + } + } + while (enb_pos > 0) { + EVAL_NUM_BUFF[enb_pos] = ' '; + enb_pos--; + } + EVAL_NUM_BUFF[enb_pos] = ' '; + EVAL_NUM_BUFF[EVAL_NUM_BUFF_SIZE - 1] = 0; + LHS = atof(EVAL_NUM_BUFF); + LHS = journal_pop(LHS); + } + LHS_pos++; + + //Remove brackets. + if (LHS_pos != 0 && RHS_pos != EVAL_LEN - 1) { + if (EVAL_BUFF[LHS_pos - 1] == '(' && EVAL_BUFF[RHS_pos + 1] == ')') { + LHS_pos--; + RHS_pos++; + } + if (LHS_pos == 1 && RHS_pos == EVAL_LEN - 2) { + LHS_pos = 0; + RHS_pos = EVAL_LEN - 1; + } + } + + if (oper == '+') { + output = LHS + RHS; + } else if (oper == '-') { + output = LHS - RHS; + } else if (oper == '*') { + output = LHS * RHS; + } else if (oper == '/') { + if (RHS == 0) output = 0; + else output = LHS / RHS; + } else if (oper == '=') { + output = LHS == RHS; + } else if (oper == '>') { + output = (ibword)LHS >> (ibword)RHS; + } else if (oper == '<') { + output = (ibword)LHS << (ibword)RHS; + } else if (oper == '%') { + output = (ibword)LHS % (ibword)RHS; + } else if (oper == '|') { + output = (ibword)LHS | (ibword)RHS; + } else if (oper == '&') { + output = (ibword)LHS & (ibword)RHS; + } else if (oper == '^') { + output = (ibword)LHS ^ (ibword)RHS; + } else if (oper == '~') { + output = LHS != RHS; + } + + + for (char i = 0; i <= LHS_pos - 1; i++) { + EVAL_BUFF[elen++] = EVAL_BUFF[i]; + } + + decimal = journal_push(output); + EVAL_BUFF[elen++] = '['; + EVAL_BUFF[elen++] = (decimal + '0'); + EVAL_BUFF[elen++] = ']'; + + for (char i = RHS_pos + 1; i < EVAL_LEN; i++) { + EVAL_BUFF[elen++] = EVAL_BUFF[i]; + } + + EVAL_LEN = elen; + + EVAL_BUFF[elen] = 0; + + +} + +//Evaluates a string stored in EVAL_BUFF. +float evaluateFormula() { + + journal_init(); + while (EVAL_LEN != 3) { + evaluateFormulaOnce(); + } + + return journal_pop(0); +} + +//Loads a formula from program memory ibwordo the EVAL_BUFF. +bool loadFormula(ibword pos) { + //012345678 + //5+(5+0*2) + +} diff --git a/src/parsing/journal.c b/src/parsing/journal.c new file mode 100755 index 0000000..1058222 --- /dev/null +++ b/src/parsing/journal.c @@ -0,0 +1,91 @@ +#define JOURNAL_MAX 8 +char JOURNAL_DATA_SIZE; +char JOURNAL_LOG_SIZE; +char JOURNAL_LOG[JOURNAL_MAX]; +float JOURNAL_DATA[JOURNAL_MAX]; + +//Initialize the journal. +void journal_init() { + JOURNAL_LOG_SIZE = 0; + JOURNAL_DATA_SIZE = 0; +} + +//Push to journal. +// Returns location pushed. +char journal_push(float a) { + if (JOURNAL_LOG_SIZE == 0) { + if (JOURNAL_DATA_SIZE == JOURNAL_MAX) { + return -1; + } else { + JOURNAL_DATA[JOURNAL_DATA_SIZE++] = a; + return JOURNAL_DATA_SIZE - 1; + } + } else { + JOURNAL_DATA[JOURNAL_LOG[JOURNAL_LOG_SIZE - 1]] = a; + JOURNAL_LOG_SIZE--; + return JOURNAL_LOG[JOURNAL_LOG_SIZE]; + } +} + +//Peek at journal. +float journal_peek(char i) { + if (i >= JOURNAL_MAX) return -1; + return JOURNAL_DATA[i]; +} + +//Pops data off of journal. +float journal_pop(char i) { + if (i < 0 || i >= JOURNAL_DATA_SIZE) return -1; + if (i == JOURNAL_DATA_SIZE - 1) { + JOURNAL_DATA_SIZE--; + return JOURNAL_DATA[JOURNAL_DATA_SIZE]; + } else { + JOURNAL_LOG[JOURNAL_LOG_SIZE++] = i; + return JOURNAL_DATA[i]; + } +} + + + +/* + + + Domains + 0 = 1:7 + 1 = 0:12 + 2 = 16:22 + 3 = 0:22 + + To determine if a side is a constant or + a variable, see if the domain of that + side is the same as the domain of another. + + Constant + Constant requires pushing a new + journal entry to store the results. + Constant + Variable or Variable + Constant + does not as we can simply store the + results inside of the variable. Variable + + Variable requires us to pop a variable + from the journal because the results + combine the two, and only one is needed to + store the results, so the other can be + discarded. + + + 0 + LHS = Constant 2 + RHS = Constant 2 + Operator = 4 + v0 = 4 + 1 + LHS = v0 + RHS = 2 + Operator = * + v0 = 8 + 2 + + + + + +*/ diff --git a/src/variables/avl.c b/src/variables/avl.c new file mode 100755 index 0000000..0bfef77 --- /dev/null +++ b/src/variables/avl.c @@ -0,0 +1,652 @@ +signed short unistrcmp(char *str_a, char *str_b) { + for (ibword i = 0;; i++) { + if (str_a[i] == 0 && str_b[i] == 0) { + return 0; + } + if (str_a[i] == 0) { + for (ibword j = i;; j++) { + if (str_b[j] == 0) { + return i - j; + } + } + } + if (str_b[i] == 0) { + for (ibword j = i;; j++) { + if (str_a[j] == 0) { + return j - i; + } + } + } + if (str_a[i] != str_b[i]) { + return str_a[i] - str_b[i]; + } + } + return 0; +} + +void unimemcpy(void *vptr_a, void *vptr_b, ibword size) { + char *ptr_a = (char*)vptr_a; + char *ptr_b = (char*)vptr_b; + for (ibword i = 0; i < size; i++) { + *(ptr_a + i) = *(ptr_b + i);; + } +} + +void ibwordToString(char *str, ibword num) { + char pos = 0; + bool negative = false; + if (num == 0) { + str[0] = '0'; + str[1] = 0; + return; + } + if (num < 0) { + num *= (ibword)-1; + negative = true; + } + while (num > 0) { + str[pos++] = (num % 10) + '0'; + num /= 10; + } + if (negative) + str[pos++] = '-'; + str[pos] = 0; + for (char i = 0; i < pos / 2; i++) { + char a = str[i]; + char b = str[pos - i - 1]; + str[i] = b; + str[pos - i - 1] = a; + } +} + + +void floatToString(char *str, float num) { + ibwordToString(str, (ibword)num); + char pos = -1; + while (str[++pos] != 0); + num = num - (ibword)num; + if (num < 0) num *= -1; + ibword places = 0; + if (num != 0) { + str[pos++] = '.'; + while (num != 0) { + num *= 10; + str[pos++] = (ibword)num + '0'; + num = num - (ibword)num; + places++; + if (places == 7) break; + } + + + str[pos] = 0; + } +} + +void printString(const char *str) { + ibword pos = 0; + char c = str[pos++]; + while (c != 0) { + writeChar(c); + c = str[pos++]; + } +} + +void printInt(ibword num) { + ibword pos = 0; + char numBuff[11]; + ibwordToString(numBuff, num); + printString(numBuff); +} + +void printFloat(float num) { + ibword pos = 0; + char numBuff[20]; + floatToString(numBuff, num); + printString(numBuff); +} + +bool isWS(char c) { + if (c == ' ' || c == '\t' || c == '\r') + return true; + return false; +} + +bool isEOL(char c) { + if (c == '\n' || c == 0 || c == 255) return true; + return false; +} + +//Checks if a character is a letter. +bool isAlpha(char c) { + if (c >= 'A' && c <= 'Z') return true; + if (c >= 'a' && c <= 'z') return true; + if (c == '_') return true; + return false; +} + +//Checks if a character is a number or a letter. +bool isAlphaNum(char c) { + if (c >= 'A' && c <= 'Z') return true; + if (c >= 'a' && c <= 'z') return true; + if (c >= '0' && c <= '9') return true; + if (c == '_') return true; + if (c == '.') return true; + return false; +} + +//Checks if a character is a number. +bool isNum(char c) { + if (c >= '0' && c <= '9') return true; + if (c == '.') return true; + return false; +} + +//Checks if a character is an operator. +bool isOperator(char c) { + if (c == '+') return true; + if (c == '-') return true; + if (c == '*') return true; + if (c == '/') return true; + if (c == '&') return true; + if (c == '|') return true; + if (c == '^') return true; + if (c == '%') return true; + if (c == '=') return true; + if (c == '~') return true; + if (c == '>') return true; + if (c == '<') return true; + return false; +} + +//Create a new node. +AVL_Node newNode(ibword address, ibword size, char *key, ibword left, ibword right) { + AVL_Node n; + n.address = address; + n.size = size; + n.left = left; + n.right = right; + if (key != NULL) { + for (char i = 0; i < KEY_SIZE; i++) { + n.key[i] = ' '; + } + for (char i = 0; i < KEY_SIZE; i++) { + if (key[i] == 0) break; + n.key[i] = key[i]; + } + n.key[KEY_SIZE] = 0; + } + n.height = 1; + n.parent = undefined; + return n; +} + +//Fetch a node from RAM. +AVL_Node fetchNode(ibword pos) { + + char buff[sizeof(AVL_Node)]; + for (char i = 0; i < sizeof(AVL_Node); i++) { + buff[i] = readRAM(i + pos); + } + + AVL_Node ret; + unimemcpy(&ret, buff, sizeof(AVL_Node)); + return ret; +} + +//Fetch a node from RAM. +AVL_Dangling fetchDangling(ibword pos) { + + char buff[sizeof(AVL_Dangling)]; + for (char i = 0; i < sizeof(AVL_Dangling); i++) { + buff[i] = readRAM(i + pos); + } + + AVL_Dangling ret; + unimemcpy(&ret, buff, sizeof(AVL_Dangling)); + return ret; +} + +//Store a node ibwordo RAM. +void storeNode(AVL_Node *n) { + char buff[sizeof(AVL_Node)]; + unimemcpy(buff, n, sizeof(AVL_Node)); + for (char i = 0; i < sizeof(AVL_Node); i++) { + writeRAM(i + n->address, buff[i]); + } +} + +//Store a node ibwordo RAM. +void storeDangling(AVL_Dangling *n, ibword address) { + char buff[sizeof(AVL_Dangling)]; + unimemcpy(buff, n, sizeof(AVL_Dangling)); + for (char i = 0; i < sizeof(AVL_Dangling); i++) { + writeRAM(i + address, buff[i]); + } +} + +//Pushes a node ibwordo RAM. +// Returns the address it was stored at. +ibword pushNode(AVL_Node *n) { + n->address = AVL_END; + AVL_END += sizeof(AVL_Node) + n->size; + char buff[sizeof(AVL_Node)]; + unimemcpy(buff, n, sizeof(AVL_Node)); + for (char i = 0; i < sizeof(AVL_Node); i++) { + writeRAM(i + n->address, buff[i]); + } + return n->address; +} + + +void updateHeight(AVL_Node *node) { + ibword leftHeight, rightHeight, height; + if (node->left == (ibword)undefined) leftHeight = 0; + else leftHeight = fetchNode(node->left).height; + if (node->right == (ibword)undefined) rightHeight = 0; + else rightHeight = fetchNode(node->right).height; + if (leftHeight > rightHeight) { + node->height = leftHeight + 1; + } else { + node->height = rightHeight + 1; + } + storeNode(node); +} + +void updateHeights(AVL_Node node) { + while (1) { + updateHeight(&node); + if (node.parent != (ibword)undefined) { + node = fetchNode(node.parent); + continue; + } + break; + } +} + +void caseLeftLeft(AVL_Node z) { + //Fetch nodes. + AVL_Node parent; + parent.address = undefined; + if (z.parent != (ibword)undefined) parent = fetchNode(z.parent); + + AVL_Node y = fetchNode(z.left); + AVL_Node T3; + T3.address = (ibword)undefined; + if (y.right != (ibword)undefined) { + T3 = fetchNode(y.right); + } + + //Update children. + if (parent.address != (ibword)undefined) { + if (parent.left == z.address) { + parent.left = y.address; + } else { + parent.right = y.address; + } + } + z.left = T3.address; + y.right = z.address; + + //Update parents. + y.parent = parent.address; + z.parent = y.address; + T3.parent = z.address; + + //Store nodes. + if (parent.address != (ibword)undefined) { + storeNode(&parent); + } + storeNode(&y); + storeNode(&z); + if (T3.address != (ibword)undefined) { + storeNode(&T3); + } + + //Update global root. + if (y.parent == (ibword)undefined) { + AVL_ROOT = y.address; + } + + //Update heights. + updateHeight(&z); + updateHeights(y); +} + +void caseRightRight(AVL_Node z) { + //Fetch nodes. + AVL_Node parent; + parent.address = undefined; + if (z.parent != (ibword)undefined) parent = fetchNode(z.parent); + + AVL_Node y = fetchNode(z.right); + AVL_Node T2; + T2.address = undefined; + if (y.left != (ibword)undefined) { + T2 = fetchNode(y.left); + } + + //Update children. + if (parent.address != (ibword)undefined) { + if (parent.left == z.address) { + parent.left = y.address; + } else { + parent.right = y.address; + } + } + z.right = T2.address; + y.left = z.address; + + //Update parents. + y.parent = parent.address; + z.parent = y.address; + T2.parent = z.address; + + //Store nodes. + if (parent.address != (ibword)undefined) { + storeNode(&parent); + } + storeNode(&y); + storeNode(&z); + if (T2.address != (ibword)undefined) { + storeNode(&T2); + } + + //Update global root. + if (y.parent == (ibword)undefined) { + AVL_ROOT = y.address; + } + + //Update heights. + updateHeight(&z); + updateHeights(y); +} + +//Rotate according to LeftRight case. +void caseLeftRight(AVL_Node z) { + //Fetch nodes. + AVL_Node parent; + parent.address = undefined; + if (z.parent != (ibword)undefined) parent = fetchNode(z.parent); + + AVL_Node y = fetchNode(z.left); + AVL_Node x = fetchNode(y.right); + AVL_Node T2, T3; + T2.address = undefined; + T3.address = undefined; + if (x.left != (ibword)undefined) { + T2 = fetchNode(x.left); + } + if (x.right != (ibword)undefined) { + T3 = fetchNode(x.right); + } + + //Update children. + if (parent.address != (ibword)undefined) { + if (parent.left == z.address) { + parent.left = x.address; + } else { + parent.right = x.address; + } + } + x.left = y.address; + x.right = z.address; + y.right = T2.address; + z.left = T3.address; + + //Update parents. + x.parent = parent.address; + y.parent = x.address; + z.parent = x.address; + T2.parent = y.address; + T3.parent = z.address; + + + //Store nodes. + if (parent.address != (ibword)undefined) { + storeNode(&parent); + } + storeNode(&x); + storeNode(&y); + storeNode(&z); + if (T2.address != (ibword)undefined) { + storeNode(&T2); + } + if (T3.address != (ibword)undefined) { + storeNode(&T3); + } + + //Update global root. + if (x.parent == (ibword)undefined) { + AVL_ROOT = x.address; + } + + //Update heights. + updateHeight(&y); + updateHeight(&z); + updateHeights(x); +} + + +void caseRightLeft(AVL_Node z) { + //Fetch nodes. + AVL_Node parent; + parent.address = undefined; + if (z.parent != (ibword)undefined) parent = fetchNode(z.parent); + + AVL_Node y = fetchNode(z.right); + AVL_Node x = fetchNode(y.left); + AVL_Node T2, T3; + T2.address = undefined; + T3.address = undefined; + if (x.left != (ibword)undefined) { + T2 = fetchNode(x.left); + } + if (x.right != (ibword)undefined) { + T3 = fetchNode(x.right); + } + + //Update children. + if (parent.address != (ibword)undefined) { + if (parent.left == z.address) { + parent.left = x.address; + } else { + parent.right = x.address; + } + } + x.left = z.address; + x.right = y.address; + z.right = T2.address; + y.left = T3.address; + + //Update parents. + x.parent = parent.address; + y.parent = x.address; + z.parent = x.address; + T2.parent = z.address; + T3.parent = y.address; + + //Store nodes. + if (parent.address != (ibword)undefined) { + storeNode(&parent); + } + storeNode(&x); + storeNode(&y); + storeNode(&z); + if (T2.address != (ibword)undefined) { + storeNode(&T2); + } + if (T3.address != (ibword)undefined) { + storeNode(&T3); + } + + //Update global root. + if (x.parent == (ibword)undefined) { + AVL_ROOT = x.address; + } + + //Update heights. + updateHeight(&y); + updateHeight(&z); + updateHeights(x); + +} + +//Calculate the balance factor of a node. +ibword getNodeBalance(AVL_Node *node) { + ibword leftHeight, rightHeight; + if (node->left == (ibword)undefined) leftHeight = 0; + else leftHeight = fetchNode(node->left).height; + if (node->right == (ibword)undefined) rightHeight = 0; + else rightHeight = fetchNode(node->right).height; + return leftHeight - rightHeight; +} + +//Inserts a new node to a tree. +// Returns the address of the node. +ibword insertNode(AVL_Node *node) { + + //Just insert the node if there are no nodes. + if (AVL_END == 0) { + node->address = AVL_ROOT; + pushNode(node); + return AVL_ROOT; + } + + AVL_Node root = fetchNode(AVL_ROOT); + AVL_Node unbalanced; + unbalanced.address = undefined; + ibword height = 0; + ibword return_val = AVL_END; + + //Go to the bottom. + while (1) { + signed short comparison = unistrcmp(node->key, root.key); + if (comparison == 0) { + return undefined; + } + + //Move down the tree. + if (comparison > 0 && root.right != (ibword)undefined) { + root = fetchNode(root.right); + height++; + continue; + } else if (comparison < 0 && root.left != (ibword)undefined) { + root = fetchNode(root.left); + height++; + continue; + } + //Insert node. + node->parent = root.address; + if (comparison > 0) root.right = pushNode(node); + else if (comparison < 0) root.left = pushNode(node); + storeNode(&root); + break; + } + + //Go back up to the top. + short balance, pbalance; + for (ibword i = 1; i <= height + 1; i++) { + if (i + 1 > root.height) { + root.height = i + 1; + storeNode(&root); + } + //Check if the balance is off. + if (unbalanced.address == (ibword)undefined) { + pbalance = balance; + balance = getNodeBalance(&root); + if (balance >= 2 || balance <= -2) { + unbalanced = fetchNode(root.address); + } + } + + if (root.parent == (ibword)undefined) break; + root = fetchNode(root.parent); + } + + //Fix balancing. + if (unbalanced.address != (ibword)undefined) { + if (balance > 0 && pbalance > 0) caseLeftLeft(unbalanced); + if (balance > 0 && pbalance < 0) caseLeftRight(unbalanced); + if (balance < 0 && pbalance < 0) caseRightRight(unbalanced); + if (balance < 0 && pbalance > 0) caseRightLeft(unbalanced); + } + + return return_val; +} + +//Finds a node's address from a given key. +ibword findNode(char *tkey) { + + //Fix spacing for search. + char key[KEY_SIZE + 1]; + for (char i = 0; i < KEY_SIZE; i++) { + key[i] = ' '; + } + for (char i = 0; i < KEY_SIZE; i++) { + if (tkey[i] == 0) break; + //Force nodes to be non-case sensitive. + if (tkey[i] >= 'a' && tkey[i] <= 'z') + tkey[i] -= 'a' - 'A'; + key[i] = tkey[i]; + } + key[KEY_SIZE] = 0; + + //Don't bother searching if there are no nodes. + if (AVL_END == 0) return undefined; + + //Fetch the root node. + AVL_Node root = fetchNode(AVL_ROOT); + AVL_Node unbalanced; + unbalanced.address = undefined; + ibword height = 0; + + //Go to the bottom. + while (1) { + signed short comparison = unistrcmp(key, root.key); + if (comparison == 0) { + return root.address; + } + + //Move down the tree. + if (comparison > 0 && root.right != (ibword)undefined) { + root = fetchNode(root.right); + continue; + } else if (comparison < 0 && root.left != (ibword)undefined) { + root = fetchNode(root.left); + continue; + } + + //Nothing found. + return undefined; + } +} + +//Pribword a node. +void printNode(AVL_Node n) { +} + +void printTree(ibword pos) { + AVL_Node n = fetchNode(pos); + printNode(n); + if (n.left != (ibword)undefined) printTree(n.left); + if (n.right != (ibword)undefined) printTree(n.right); +} + +//Verifies that a key is valid. +bool verifyKey(char *key) { + char p = 0; + char c = key[p++]; + if (c == '@' || c == '$') { + c = key[p++]; + } + if (c == 0) return false; + if (!isAlpha(c)) return false; + c = key[p++]; + while (c != 0) { + if (!isAlphaNum(c) || c == '.') + return false; + c = key[p++]; + } + if (p > KEY_SIZE) return false; + return true; +} diff --git a/src/variables/avl.h b/src/variables/avl.h new file mode 100755 index 0000000..d44700e --- /dev/null +++ b/src/variables/avl.h @@ -0,0 +1,88 @@ +#include "../hardware/hardware.h" +#define KEY_SIZE 16 +ibword AVL_ROOT = 0; +ibword AVL_END = 0; +typedef struct _avl_node { + char key[KEY_SIZE + 1]; + ibword left; + ibword right; + ibword address; + ibword size; + ibword parent; + ibword height; + ibword next; +} AVL_Node; +typedef struct _dangling_node { + ibword next; + ibword size; +} AVL_Dangling; + +//Create a new node. +AVL_Node newNode(ibword address, ibword size, char *key, ibword left, ibword right); + +//Fetch a node from RAM. +AVL_Node fetchNode(ibword pos); + +//Store a node ibwordo RAM. +void storeNode(AVL_Node *n); + +//Pushes a node ibwordo RAM. +// Returns the address it was stored at. +ibword pushNode(AVL_Node *n); + +//Update the height of a single node. +void updateHeight(AVL_Node *node); + +//Update the height of a node and all its ancestors. +void updateHeights(AVL_Node node); + +//AVL tree Left-Left case. +void caseLeftLeft(AVL_Node z); + +//AVL tree Right-Right case. +void caseRightRight(AVL_Node z); + +//AVL tree Left-Right case; +void caseLeftRight(AVL_Node z); + +//AVL tree Right-Left case. +void caseRightLeft(AVL_Node z); + +//Calculate the balance factor of a node. +ibword getNodeBalance(AVL_Node *node); + +//Inserts a new node to a tree. +// Returns the address of the node. +ibword insertNode(AVL_Node *node); + +//Pribword a node. +//void printNode(AVL_Node n); + +//Pribword an entire tree whose root is located as pos. +void printTree(ibword pos); + +//Find a node from a given key. +ibword findNode(char *key); + +//Verifies that a key for a node is valid. +bool verifyKey(char *key); + +//Checks if a character is a letter. +bool isAlpha(char c); + +//Checks if a character is a number or a letter. +bool isAlphaNum(char c); + +//Checks if a character is a number. +bool isNum(char c); + +//Checks if a character is an operator. +bool isOperator(char c); + +//Checks if a character is a whitespace character. +bool isWS(char c); + +//Checks if a character is an end of line character. +bool isEOL(char c); + +#include "avl.c" diff --git a/src/variables/variables.c b/src/variables/variables.c new file mode 100755 index 0000000..a0bed0b --- /dev/null +++ b/src/variables/variables.c @@ -0,0 +1,162 @@ +#include "avl.h" + +//Creates a number variable. +void dimNum(char *name, float value) { + + //Create the node. + AVL_Node n = newNode(undefined, sizeof(float), name, undefined, undefined); + ibword address = insertNode(&n); + + //Store value ibwordo node. + char buffer[sizeof(float)]; + unimemcpy(buffer, &value, sizeof(float)); + for (char i = 0; i < sizeof(float); i++) { + writeRAM(address + sizeof(AVL_Node) + i, buffer[i]); + } + +} + +//Creates a number array. +void dimArr(char *name, ibword size) { + + //Create the node. + AVL_Node n = newNode(undefined, size * sizeof(float), name, undefined, undefined); + insertNode(&n); + +} + +//Creates an address variable. +void dimAdr(char *name, ibword value) { + + //Create the node. + AVL_Node n = newNode(undefined, sizeof(ibword), name, undefined, undefined); + ibword address = insertNode(&n); + + //Store value ibwordo node. + char buffer[sizeof(ibword)]; + unimemcpy(buffer, &value, sizeof(ibword)); + for (char i = 0; i < sizeof(ibword); i++) { + writeRAM(address + sizeof(AVL_Node) + i, buffer[i]); + } + +} + +//Creates a string variable. +ibword dimStr(char *name, ibword size) { + //Create the node. + AVL_Node n = newNode(undefined, size, name, undefined, undefined); + n.next = undefined; + ibword addr = insertNode(&n); + //If the size > 0, set the first value to 0. + if (size > 0) + writeRAM(addr + sizeof(AVL_Node), 0); + return addr; +} + +//Reads a number variable at an address. +float readNum(ibword address) {; + float value; + //Store value ibwordo node. + char buffer[sizeof(float)]; + for (char i = 0; i < sizeof(float); i++) { + buffer[i] = readRAM(address + sizeof(AVL_Node) + i); + } + unimemcpy(&value, buffer, sizeof(float)); + return value; +} + +//Creates a dangling node. +//These nodes are inserted into the list of nodes in the AVL +// tree but no other nodes point to them. +//They can thus be used to store information between nodes +// inside the AVL tree without interfering with the tree's +// structure itself. +ibword insertDanglingNode(ibword size) { + //Create the node. + AVL_Node n = newNode(AVL_END, size, NULL, undefined, undefined); + n.next = undefined; + AVL_END += sizeof(AVL_Node) + size; + storeNode(&n); + return n.address; +} + +//Reads an address variable at an address. +ibword readAdr(ibword address) {; + ibword value; + //Store value ibwordo node. + char buffer[sizeof(ibword)]; + for (char i = 0; i < sizeof(ibword); i++) { + buffer[i] = readRAM(address + sizeof(AVL_Node) + i); + } + unimemcpy(&value, buffer, sizeof(ibword)); + return value; +} + +//Reads a character from a string variable at an address at a given index. +char readStr(ibword address, ibword index) { + AVL_Node n = fetchNode(address); + while (index >= n.size) { + index -= n.size; + n = fetchNode(n.next); + } + //Return value. + return readRAM(n.address + sizeof(AVL_Node) + index); +} + +//Reads an array at an index. +float readArr(ibword address, ibword index) { + //Return value; + float ret; + char *ptr = (char*)(&ret); + for (char i = 0; i < sizeof(float); i++) + ptr[i] = readRAM(address + sizeof(AVL_Node) + index * sizeof(float) + i); + return ret; +} + +//Writes an array at an index. +void writeArr(ibword address, ibword index, float val) { + //Return value; + char *ptr = (char*)(&val); + for (char i = 0; i < sizeof(float); i++) + writeRAM(address + sizeof(AVL_Node) + index * sizeof(float) + i, ptr[i]); +} + + +//Reads a number variable at an address. +void writeNum(ibword address, float value) { + //Store value ibwordo node. + char buffer[sizeof(float)]; + unimemcpy(buffer, &value, sizeof(float)); + for (char i = 0; i < sizeof(float); i++) { + writeRAM(address + sizeof(AVL_Node) + i, buffer[i]); + } +} + +//Reads a number variable at an address. +bool writeStr(ibword address, ibword index, char c) { + AVL_Node n = fetchNode(address); + while (index >= n.size) { + index -= n.size; + n = fetchNode(n.next); + } + //Return value. + writeRAM(n.address + sizeof(AVL_Node) + index, c); +} + +//Reads size of a string. +ibword readStrSize(ibword address) { + ibword size; + AVL_Node n = fetchNode(address); + size = n.size; + while (n.next != (ibword)undefined) { + n = fetchNode(n.next); + size += n.size; + } + return size; +} + +//Reads size of a string. +ibword readArrSize(ibword address) { + AVL_Node n = fetchNode(address); + return n.size / sizeof(float); +} -- 2.39.5